Dual-Booting FreeBSD and Linux¶
How to put Debian (the same approach works for most Linux distributions) next to an existing FreeBSD install on the same disk, boot either one, and share data between them. The main path assumes a UEFI machine with a GPT disk, which covers anything built in the last decade; legacy BIOS/MBR notes are in Section 7.
1. Plan the Disk Space First¶
Neither of FreeBSD's root filesystems can be shrunk:
- ZFS: a pool can't be shrunk by making its partition smaller.
- UFS:
growfsonly grows; there's no shrink tool.
So the space for Linux has to be unpartitioned free space that already exists. Either:
- Leave free space when installing FreeBSD (choose Manual or Shell partitioning in
bsdinstall, or set a smaller ZFS partition size in the guided installer), or - Add a second disk for Linux. This is simpler and safer: each OS gets its own disk, and a reinstall of one can't touch the other.
If FreeBSD already fills the disk, back it up and reinstall with room to spare, or use a second disk.
Check what you have:
gpart show ada0 # or nda0 for NVMe
=> 40 500118112 ada0 GPT (238G)
40 532480 1 efi (260M)
532520 1024 2 freebsd-boot (512K)
533544 4194304 3 freebsd-swap (2.0G)
4727848 167772160 4 freebsd-zfs (80G)
172500008 327618144 - free - (156G)
The - free - line is where Linux will go. Note the efi partition (index 1) - Linux will share it.
2. Prepare FreeBSD¶
2.1 Confirm the FreeBSD EFI loader location¶
Recent FreeBSD installers mount the EFI system partition (ESP) at /boot/efi and install the loader in two places:
ls -R /boot/efi/efi
# /boot/efi/efi/boot/bootx64.efi <- the removable-media fallback path
# /boot/efi/efi/freebsd/loader.efi <- FreeBSD's own entry
If you only have efi/boot/bootx64.efi, copy it to its own directory so the Linux installer can't overwrite FreeBSD's only loader, and register it with the firmware:
mkdir -p /boot/efi/efi/freebsd
cp /boot/loader.efi /boot/efi/efi/freebsd/loader.efi
efibootmgr -a -c -l /boot/efi/efi/freebsd/loader.efi -L FreeBSD
If /boot/efi isn't mounted, mount the ESP first: mount -t msdosfs /dev/ada0p1 /boot/efi.
2.2 Optionally pre-create the Linux partitions¶
You can let the Debian installer partition the free space itself (simplest, Section 3), or create labelled partitions from FreeBSD so there's no doubt which space is which:
gpart add -t linux-swap -s 4G -l linuxswap ada0
gpart add -t linux-data -s 60G -l linuxroot ada0
gpart add -t linux-data -l linuxhome ada0 # rest of the free space
gpart show -l ada0
New partitions take the next free index numbers, so existing FreeBSD partitions keep their names (ada0p4 stays ada0p4).
2.3 Take a safety net¶
bectl create pre-dualboot # ZFS root: a boot environment to fall back to
gpart backup ada0 > /root/ada0.gpt # partition table backup (copy it off the machine too)
efibootmgr -v > /root/efibootmgr.before # record current boot entries
3. Install Linux¶
Boot the Debian installer from USB in UEFI mode (the firmware boot menu usually lists the stick twice; pick the "UEFI:" entry). The steps that matter:
- At Partition disks, choose Manual. Avoid the guided options that offer to "use entire disk."
- Assign the free space, or the partitions you created:
-
linuxroot-> ext4, mount point/-linuxhome-> ext4, mount point/home(optional) -linuxswap-> swap area - Select the existing EFI System Partition and set it to "Use as: EFI System Partition". Do not format it - it holds FreeBSD's loader.
- Leave the FreeBSD partitions (
freebsd-boot,freebsd-swap,freebsd-zfs/freebsd-ufs) set to "do not use." - Finish the install. GRUB installs to
/EFI/debian/on the shared ESP and makes itself the first firmware boot entry.
4. Add FreeBSD to the GRUB Menu¶
os-prober doesn't reliably detect FreeBSD, so add a menu entry by hand. Boot into Debian, then find the ESP's filesystem UUID:
sudo blkid /dev/sda1 # or: sudo grub-probe --target=fs_uuid /boot/efi
# /dev/sda1: UUID="ABCD-1234" TYPE="vfat" PARTLABEL="efiboot0" ...
Add a chainload entry to /etc/grub.d/40_custom (append below the existing header lines):
menuentry "FreeBSD" {
insmod part_gpt
insmod fat
search --no-floppy --fs-uuid --set=root ABCD-1234
chainloader /efi/freebsd/loader.efi
}
Regenerate the config:
sudo update-grub
GRUB hands off to FreeBSD's own loader.efi, which then shows the normal FreeBSD boot menu (including boot environments on ZFS). GRUB doesn't need to understand ZFS or UFS for this to work.
To make the GRUB menu wait long enough to choose, set GRUB_TIMEOUT=10 in /etc/default/grub and run update-grub again.
5. Managing Boot Order Without GRUB¶
You don't have to route FreeBSD through GRUB. The firmware boot manager can choose between them directly, and both systems can edit it.
From FreeBSD:
efibootmgr -v # list entries: Boot0001* FreeBSD, Boot0002* debian, ...
efibootmgr -o 0001,0002 # set the default order (FreeBSD first)
efibootmgr -n -b 0002 # boot Debian once on the next reboot only
efibootmgr -a -b 0001 # mark an entry active
From Linux:
sudo efibootmgr -v
sudo efibootmgr -o 0001,0002
sudo efibootmgr -n 0001 # boot FreeBSD once on the next reboot
The one-time -n boot is handy for remote machines: reboot into the other OS once, and a second reboot returns to the default.
Most firmware also has a boot menu key (often F8, F11, F12 or Esc) for picking an entry at power-on. A graphical boot manager such as rEFInd is another option if you'd rather not depend on either OS's loader.
6. Sharing Data Between FreeBSD and Linux¶
6.1 Reading Linux filesystems from FreeBSD¶
FreeBSD's ext2fs driver handles ext2, ext3 and ext4:
kldload ext2fs
mkdir -p /mnt/linux
mount -t ext2fs /dev/gpt/linuxhome /mnt/linux
FreeBSD doesn't replay the ext4 journal, so only write to a Linux filesystem that Linux shut down cleanly; mount with -o ro if in doubt. More detail in FreeBSD SysAdmin Essentials (section 4.3).
6.2 Reading FreeBSD filesystems from Linux¶
UFS (read-only is the safe choice; Linux's UFS write support is experimental):
sudo mount -t ufs -o ufstype=ufs2,ro /dev/sda4 /mnt/freebsd
ZFS with OpenZFS on Linux (zfsutils-linux on Debian):
sudo zpool import # list importable pools
sudo zpool import -N -o readonly=on -R /mnt/freebsd zroot
sudo zfs mount zroot/usr/home # mount just what you need
sudo zpool export zroot # always export before booting FreeBSD again
- Import read-only unless you have a reason not to, and always export before rebooting into FreeBSD. A pool left imported by Linux needs
zpool import -ffrom FreeBSD, and on a root pool that means a trip to the rescue shell. - Never run
zpool upgradefrom one OS without checking the other supports every feature it enables, or the other OS will refuse to import the pool. The OpenZFScompatibilitypool property can pin a pool to a feature set both sides support. - Mounting FreeBSD's root boot environment on Linux is rarely useful; mount data datasets like
zroot/usr/home.
6.3 A shared data partition¶
For files you use from both systems, a dedicated partition avoids cross-OS filesystem caveats entirely:
- ext4: native on Linux, read-write on FreeBSD via
ext2fs. Good default. - exFAT: native on Linux, FUSE on FreeBSD (
fusefs-exfat). Good if the data also travels on USB to Windows/macOS. - ZFS (a separate small pool): both systems are first-class, as long as you mind the feature-flag rule above.
6.4 Clock¶
FreeBSD and Debian both keep the hardware clock in UTC by default, so they agree out of the box. If one shows the wrong time after switching, check FreeBSD for /etc/wall_cmos_clock (its presence means "hardware clock is local time") and Linux with timedatectl (RTC in local TZ: no is what you want).
7. Legacy BIOS / MBR Systems¶
On an old machine booting in legacy BIOS mode with an MBR disk, the pieces are different:
- Partitions are MBR slices. FreeBSD typically lives in slice 1 (
ada0s1, type 165/freebsd), with its own BSD partitions inside (ada0s1a, ...). Add Linux slices in free space withgpart add -t linux-data ada0(MBR type 131) andgpart add -t linux-swap ada0(type 130). MBR allows only four primary slices. - GRUB 2 chainloads FreeBSD's boot block:
menuentry "FreeBSD" {
insmod part_msdos
set root=(hd0,msdos1)
chainloader +1
}
- Writing the MBR from a running FreeBSD system fails with "Unable to write data to disk" or
Operation not permitted, because GEOM protects disks with mounted partitions. Temporarily allow it, do the write, then turn the protection back on:
sh
sysctl kern.geom.debugflags=16
# ... gpart bootcode / write the MBR ...
sysctl kern.geom.debugflags=0
- FreeBSD's boot manager (
boot0) can also choose between slices without GRUB:gpart bootcode -b /boot/boot0 ada0gives anF1 FreeBSD / F2 Linuxmenu at power-on, with GRUB installed to the Linux slice rather than the MBR.
Old notes that install sysutils/grub (GRUB legacy) on FreeBSD, use menu.lst, or boot the Debian installer from vmlinuz/initrd.gz files placed in /boot are from the floppy and GRUB 0.97 era. Booting the installer from USB and letting Debian install GRUB 2 replaces all of that.
8. Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
| Machine boots straight into Debian with no FreeBSD option | Debian's GRUB is first in the firmware order and has no FreeBSD entry | Add the GRUB entry (Section 4), or efibootmgr -o to put FreeBSD first (Section 5) |
GRUB "FreeBSD" entry errors with file not found |
Wrong ESP UUID or loader path | Re-check blkid and that /efi/freebsd/loader.efi exists on the ESP (paths are case-insensitive on FAT) |
| FreeBSD no longer boots at all after the Linux install | ESP was formatted, or the fallback bootx64.efi was overwritten and was FreeBSD's only loader |
Boot FreeBSD install media -> Shell, mount the ESP, copy /boot/loader.efi back to efi/freebsd/loader.efi and efibootmgr -c a new entry |
| FreeBSD boots but can't mount root | /etc/fstab refers to a partition that was changed during the Linux install |
Boot to single-user, fix /etc/fstab; prefer /dev/gpt/<label> names |
| Debian installer only offers "use entire disk" | Installer booted in legacy BIOS mode on a UEFI/GPT system | Reboot and pick the "UEFI:" entry for the USB stick |
| ZFS pool won't import on FreeBSD after using it from Linux | Pool still marked as imported by Linux, or upgraded with Linux-only features | zpool import -f; for features, there's no downgrade - restore from backup |
Unable to write data to disk when editing partitions on BIOS/MBR |
GEOM write protection on a disk in use | sysctl kern.geom.debugflags=16, then set back to 0 (Section 7) |
References¶
- FreeBSD Handbook: The FreeBSD Booting Process
- FreeBSD Handbook: Other File Systems
man 8 efibootmgr,man 8 gpart,man 8 uefi,man 8 loader.efi,man 5 ext2fs,man 8 boot0cfg- Debian: UEFI and GRUB wiki pages