Dusko Pijetlovic

My personal notes where I store things I find interesting or might need in the future.

FreeBSD ZFS and Windows 11 Dual Boot [UEFI GPT] [Manual Setup]

26 Feb 2025 » zfs, freebsd, windows, boot, howto, cli, terminal, shell, disk

aka: RootOnZFS, GPTZFSBoot, ZFSBoot

OS 1: FreeBSD 14
OS 2: Windows 11 Pro


KEYWORDS: FreeBSD ZFS RootOnZFS GPTZFSBoot ZFSBOOT UEFI GPT dualboot boot bootloader bootmanager rEFInd readonly writeable gpart geom zpool zfs label labelclear unionfs tmpfs manualinstall live livesystem liveCD ramdisk md(4) mdconfig(8) mdmfs(8)


Code Snippets

Reboot
F12
Select 'USB HDD'
FreeBSD Loader starts
Select '1. Boot Installer [Enter]"
FreeBSD Installer


    +-------------------------------------------+
    | welcome to FreeBSD! Would you like to     |
    | begin an installation or use the live     |
    | system?                                   |
    +-------------------------------------------+
    | [  Install  ] [   Shell   ] [Live System] |
    +-------------------------------------------+
Select  [   Shell   ]

(It will show the following message:)
"When finished, type 'exit' to return to the installer."
# kldload unionfs
# mkdir /tmp/etc /tmp/root
# mount -t unionfs /tmp/etc /etc
# mount -t unionfs /tmp/root /root

# ifconfig
---- snip ---
re0: flags=1008802<BROADCAST,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
---- snip ---

# dhclient re0
---- snip ---
bound to 192.168.1.7 -- renewal in 43200 seconds.

# printf %s\\n "PermitRootLogin yes" >> /etc/ssh/sshd_config
# service sshd onestart
# passwd
### From another machine on the same network, remotely log in with SSH
ssh root@192.168.1.7

# mkdir /tmp/zroot
# kldload zfs

### Check for existence of previous ZFS pools
# zpool import
no pools available to import
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### If there are any, destroy them and clear labels
# zpool import -o altroot=/tmp/zroot zroot
# zpool destroy zroot

# gpart show -lp nda1
### Example output:
=>        34  3907029101    nda1  GPT  (1.8T)
          34        2014          - free -  (1.0M)
        2048      532480  nda1p1  EFI system partition  (260M)
      534528       32768  nda1p2  Microsoft reserved partition  (16M)
      567296  1801259008  nda1p3  Basic data partition  (859G)
  1801826304     4096000  nda1p4  Basic data partition  (2.0G)
  1805922304    16777216  nda1p5  tPadE14-swap0  (8.0G)
  1822699520  2076180480  nda1p6  tPadE14-zfs0  (990G)
  3898880000     8149135          - free -  (3.9G)

# zpool labelclear -f /dev/nda1
# zpool labelclear -f /dev/nda1p1
# zpool labelclear -f /dev/nda1p2
# zpool labelclear -f /dev/nda1p3
# zpool labelclear -f /dev/nda1p4
# zpool labelclear -f /dev/nda1p5
# zpool labelclear -f /dev/nda1p6

### To check:
# zdb -llll -d /dev/nda1
# zdb -llll -d /dev/nda1p1
# zdb -llll -d /dev/nda1p2
# zdb -llll -d /dev/nda1p3
# zdb -llll -d /dev/nda1p4
# zdb -llll -d /dev/nda1p5
# zdb -llll -d /dev/nda1p6

# glabel stop /dev/gpt/tPadE14-swap0
# glabel stop /dev/gpt/tPadE14-zfs0
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Continue with installation

### From 'gpart show -lp nda1' example above, the previous installation attempt
### left partitions at index 5 and index 6.  They can be deleted for this
### new fresh installation.

# gpart delete -i5 nda1
# gpart delete -i6 nda1

# gpart show -lp nda1
=>        34  3907029101    nda1  GPT  (1.8T)
          34        2014          - free -  (1.0M)
        2048      532480  nda1p1  EFI system partition  (260M)
      534528       32768  nda1p2  Microsoft reserved partition  (16M)
      567296  1801259008  nda1p3  Basic data partition  (859G)
  1801826304     4096000  nda1p4  Basic data partition  (2.0G)
  1805922304  2101106831          - free -  (1.0T)


# sysctl vfs.zfs.min_auto_ashift=12

# gpart add -a 1m -t freebsd-swap -s 16G -l tPadE14-swap0 nda1
# gpart add -a 1m -t freebsd-zfs -s 980G -l tPadE14-zfs0 nda1

# zpool create -f -o altroot=/tmp/zroot -O compress=lz4 -O atime=off -m none zroot /dev/gpt/tPadE14-zfs0

### Alternatively, you could have used ZFS partition name:
### zpool create -f -o altroot=/tmp/zroot -O compress=lz4 -O atime=off -m none zroot nda1p6

### Test zpool export, then import
# zpool export zroot
# zpool import -o altroot=/tmp/zroot zroot

# zfs create -o mountpoint=none zroot/ROOT
# zfs create -o mountpoint=/ zroot/ROOT/default
# zfs create -o mountpoint=/tmp -o exec=on -o setuid=off zroot/tmp
# zfs create -o mountpoint=/usr -o canmount=off zroot/usr
# zfs create zroot/usr/home
# zfs create -o setuid=off zroot/usr/ports
# zfs create -o mountpoint=/var -o canmount=off zroot/var
# zfs create -o exec=off -o setuid=off zroot/var/audit
# zfs create -o exec=off -o setuid=off zroot/usr/src
# zfs create -o exec=off -o setuid=off zroot/var/crash
# zfs create -o exec=off -o setuid=off zroot/var/log
# zfs create -o atime=on zroot/var/mail
# zfs create -o setuid=off zroot/var/tmp

# zpool set bootfs=zroot/ROOT/default zroot
# zpool set cachefile=/tmp/boot/zfs/zpool.cache zroot    ### [1] 

# chmod 1777 /tmp/zroot/tmp/
# chmod 1777 /tmp/zroot/var/tmp/

# cd /tmp/zroot/
# ln -s usr/home home

# tar xpJf /usr/freebsd-dist/base.txz
# tar xpJf /usr/freebsd-dist/lib32.txz
# tar xpJf /usr/freebsd-dist/kernel.txz

### Make sure that ZFS is started at boot.
### This mounts your filesystem datasets at boot.
# printf %s\\n 'zfs_enable="YES"' >> /tmp/zroot/etc/rc.conf

### Tell FreeBSD to load ZFS and related kernel modules at boot.
# printf %s\\n 'zfs_load="YES"' >> /tmp/zroot/boot/loader.conf

# printf %s\\n 'kern.geom.label.disk_ident.enable="0"' >> /tmp/zroot/boot/loader.conf
# printf %s\\n 'kern.geom.label.gptid.enable="0"' >> /tmp/zroot/boot/loader.conf

# printf "/dev/gpt/tPadE14-swap0\tnone\tswap\tsw\t0\t0\n" >> /tmp/zroot/etc/fstab

# cd /tmp/
# fetch https://netactuate.dl.sourceforge.net/project/refind/0.14.2/refind-bin-0.14.2.zip

# unzip refind-bin-0.14.2.zip
# rm -i refind-bin-0.14.2.zip

# mkdir /tmp/efi
# mount -t msdosfs /dev/gpt/EFI%20system%20partition /tmp/efi/

# cd /tmp/efi/EFI/Boot/
# mv bootx64.efi bootx64-win.efi
# cp -i /boot/loader.efi bootx64-freebsd.efi
# cp -i /tmp/refind-bin-0.14.2/refind/refind_x64.efi bootx64-refind.efi
# cp -i /tmp/refind-bin-0.14.2/refind/refind.conf-sample refind.conf
# cp -a /tmp/refind-bin-0.14.2/refind/icons .

# vi refind.conf

# tail refind.conf

menuentry "FreeBSD/amd64 -RELEASE" {
    loader \EFI\Boot\bootx64-freebsd.efi
    icon \EFI\Boot\icons\os_freebsd.png
}

menuentry "Windows 11 Professional x64" {
    loader \EFI\Boot\bootx64-windows11.efi
    icon \EFI\Boot\icons\os_win.png
}

# efibootmgr -v
---- snip ----

# efibootmgr --dry-run --verbose --create --activate --label "FreeBSD" --loader "/tmp/efi/EFI/Boot/bootx64-refind.efi"
# efibootmgr --verbose --create --activate --label "FreeBSD" --loader "/tmp/efi/EFI/Boot/bootx64-refind.efi"
# efibootmgr --create --loader "/tmp/efi/EFI/Boot/bootx64-refind.efi" --label "rEFInd" --activate --dry-run
# efibootmgr --create --loader "/tmp/efi/EFI/Boot/bootx64-refind.efi" --label "rEFInd" --activate

# efibootmgr -v
---- snip ----

# cd /tmp
# umount /tmp/efi/
# reboot

Unplug the FreeBSD Installer USB flash disk drive.

After reboot, you will need to create the root password (at this point, the root password is empty). Log in as root using the system’s console, and continue setting up the new machine.

FreeBSD/amd64 (Amnesiac) (ttyv0)
login:

It’s not recommended to enable PermitRootLogin again but if you wanted to, you would need to perform the following steps.

# dhclient re0
# cp -i /etc/ssh/sshd_config /etc/ssh/sshd_config.ORIG
# printf %s\\n "PermitRootLogin yes" >> /etc/ssh/sshd_config
# service sshd onestart
# passwd

Overview

General Overview

  • Create a partition to reserve space for FreeBSD (to prevent the Windows installer from using the entire disk)
  • Install Windows
  • Install FreeBSD
  • (Optional) Install an EFI boot manager (such as rEFInd), or use the bootmanager of the EFI firmware

  • Shrink the disk from within Windows, then install FreeBSD.
  • If the installer does not recognize the unallocated space, try manually partitioning from within the installer, and if that doesn’t work, go to a live FreeBSD session to partition, then reboot and install.

Tips and Tricks

  • If you need network connection during FreeBSD installation, it’s better to use Ethernet (wired networking) because WiFi (wireless network) can be unreliable.

  • You just need a Live FreeBSD enviroment to conduct your manual install. Make sure it is 11.0 or newer for UEFI boot1 ZFS support. The USB images with FreeBSD 11.0 and later -RELEASE have UEFI support integrated so they are directly bootable on UEFI machines. You could also use a CD/DVD or netboot.

  • In FreeBSD installer, when you choose [Live System], then /mnt will be read-only. Similarly, when you choose [ Shell ], then /mnt will also be read-only.

You don’t need /mnt to be writeable. Instead, you can use unionfs for /etc and /root.

# mkdir /tmp/etc /tmp/root
# mount -t unionfs /tmp/etc /etc
# mount -t unionfs /tmp/root /root

If do want a writeable /mnt, you can unionfs for it too, or you can use mdmfs, mount_mfs(8) to configure and mount an in-memory file system using the md 4 driver (see man 4 md) or the tmpfs 5 filesystem (see man 5 tmpfs).

  • In my tests, using sed(1) in FreeBSD installer for modifying sshd_config caused a crash.
# sed -i.bak "s/PermitRootLogin no/PermitRootLogin yes/" /etc/ssh/sshd_config

Using vi(1) to edit sshd_config worked. (# vi /etc/ssh/sshd_config)


References