Bookworm (12) UEFI#

This guide can be used to install Debian onto a single disk with or without ZFS encryption.

It assumes the following:

  • Your system uses UEFI to boot

  • Your system is x86_64

  • You're mildly comfortable with ZFS, EFI and discovering system facts on your own (lsblk, dmesg, gdisk, ...)

Download the latest Debian Bookworm (12) Live image, write it to a USB drive and boot your system in EFI mode.

Confirm EFI support:

# dmesg | grep -i efivars
[    0.301784] Registered efivars operations

Configure Live Environment#

Switch to a root shell#

sudo -i

Source /etc/os-release#

The file /etc/os-release defines variables that describe the running distribution. In particular, the $ID variable defined within can be used as a short name for the filesystem that will hold this installation.

source /etc/os-release
export ID

Configure and update APT#

cat <<EOF > /etc/apt/sources.list
deb bookworm main contrib
deb-src bookworm main contrib
apt update


You may see faster downloads replacing with a local mirror. If you want to use HTTPS transport, make sure that the ca-certificates and apt-transport-https packages are installed and your mirror has a valid certificate; otherwise, apt will refuse to use the mirror.

Install helpers#

apt install debootstrap gdisk dkms linux-headers-$(uname -r)
apt install zfsutils-linux

Generate /etc/hostid#

zgenhostid -f 0x00bab10c

Define disk variables#

For convenience and to reduce the likelihood of errors, set environment variables that refer to the devices that will be configured during the setup.

For many users, it is most convenient to place boot files (i.e., ZFSBootMenu and any loader responsible for launching it) on the the same disk that will hold the ZFS pool. However, some users may wish to dedicate an entire disk to the ZFS pool or create a multi-disk pool. A USB flash drive provides a convenient location for the boot partition. Fortunately, this alternative configuration is easily realized by simply defining a few environment variables differently.

Verify your target disk devices with lsblk. /dev/sda, /dev/sdb and /dev/nvme0n1 used below are examples.

First, define variables that refer to the disk and partition number that will hold boot files:

export BOOT_DISK="/dev/sda"
export BOOT_PART="1"

Next, define variables that refer to the disk and partition number that will hold the ZFS pool:

export POOL_DISK="/dev/sda"
export POOL_PART="2"

Disk preparation#

Wipe partitions#

zpool labelclear -f "$POOL_DISK"

wipefs -a "$POOL_DISK"
wipefs -a "$BOOT_DISK"

sgdisk --zap-all "$POOL_DISK"
sgdisk --zap-all "$BOOT_DISK"

Create EFI boot partition#

sgdisk -n "${BOOT_PART}:1m:+512m" -t "${BOOT_PART}:ef00" "$BOOT_DISK"

Create zpool partition#

sgdisk -n "${POOL_PART}:0:-10m" -t "${POOL_PART}:bf00" "$POOL_DISK"

ZFS pool creation#

Create the zpool#

zpool create -f -o ashift=12 \
 -O compression=lz4 \
 -O acltype=posixacl \
 -O xattr=sa \
 -O relatime=on \
 -o autotrim=on \
 -o compatibility=openzfs-2.1-linux \
 -m none zroot "$POOL_DEVICE"


The option -o compatibility=openzfs-2.1-linux is a conservative choice. It can be omitted or otherwise adjusted to match your specific system needs.

Binary releases of ZFSBootMenu are generally built with the latest stable release of ZFS. Future releases of ZFSBootMenu may therefore support newer feature sets. Check project release notes prior to updating or removing compatibility options and upgrading your system pool.

Create initial file systems#

zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/${ID}
zfs create -o mountpoint=/home zroot/home

zpool set bootfs=zroot/ROOT/${ID} zroot


It is important to set the property canmount=noauto on any file systems with mountpoint=/ (that is, on any additional boot environments you create). Without this property, the OS will attempt to automount all ZFS file systems and fail when multiple file systems attempt to mount at /; this will prevent your system from booting. Automatic mounting of / is not required because the root file system is explicitly mounted in the boot process.

Also note that, unlike many ZFS properties, canmount is not inheritable. Therefore, setting canmount=noauto on zroot/ROOT is not sufficient, as any subsequent boot environments you create will default to canmount=on. It is necessary to explicitly set the canmount=noauto on every boot environment you create.

Export, then re-import with a temporary mountpoint of /mnt#

zpool export zroot
zpool import -N -R /mnt zroot
zfs mount zroot/ROOT/${ID}
zfs mount zroot/home

Verify that everything is mounted correctly#

# mount | grep mnt
zroot/ROOT/debian on /mnt type zfs (rw,relatime,xattr,posixacl)
zroot/home on /mnt/home type zfs (rw,relatime,xattr,posixacl)

Install Debian#

debootstrap bookworm /mnt

Copy files into the new install#

cp /etc/hostid /mnt/etc
cp /etc/resolv.conf /mnt/etc

Chroot into the new OS#

mount -t proc proc /mnt/proc
mount -t sysfs sys /mnt/sys
mount -B /dev /mnt/dev
mount -t devpts pts /mnt/dev/pts
chroot /mnt /bin/bash

Basic Debian Configuration#

Set a hostname#

echo 'YOURHOSTNAME' > /etc/hostname
echo -e '\tYOURHOSTNAME' >> /etc/hosts

Set a root password#


Configure apt. Use other mirrors if you prefer.

cat <<EOF > /etc/apt/sources.list
deb bookworm main contrib
deb-src bookworm main contrib

deb bookworm-security main contrib
deb-src bookworm-security main contrib

deb bookworm-updates main contrib
deb-src bookworm-updates main contrib

deb bookworm-backports main contrib
deb-src bookworm-backports main contrib

Update the repository cache#

apt update

Install additional base packages#

apt install locales keyboard-configuration console-setup

Configure packages to customize local and console properties#

dpkg-reconfigure locales tzdata keyboard-configuration console-setup


You should always enable the en_US.UTF-8 locale because some programs require it.

ZFS Configuration#

Install required packages#

apt install linux-headers-amd64 linux-image-amd64 zfs-initramfs dosfstools
echo "REMAKE_INITRD=yes" > /etc/dkms/zfs.conf

Enable systemd ZFS services#

systemctl enable
systemctl enable zfs-import-cache
systemctl enable zfs-mount
systemctl enable

Configure initramfs-tools#

No required steps

Rebuild the initramfs#

update-initramfs -c -k all

Install and configure ZFSBootMenu#

Set ZFSBootMenu properties on datasets#

Assign command-line arguments to be used when booting the final kernel. Because ZFS properties are inherited, assign the common properties to the ROOT dataset so all children will inherit common arguments by default.

zfs set org.zfsbootmenu:commandline="quiet" zroot/ROOT

Create a vfat filesystem#

mkfs.vfat -F32 "$BOOT_DEVICE"

Create an fstab entry and mount#

cat << EOF >> /etc/fstab
$( blkid | grep "$BOOT_DEVICE" | cut -d ' ' -f 2 ) /boot/efi vfat defaults 0 0

mkdir -p /boot/efi
mount /boot/efi

Install ZFSBootMenu#

apt install curl

Fetch a prebuilt ZFSBootMenu EFI executable, saving it to the EFI system partition:

mkdir -p /boot/efi/EFI/ZBM
curl -o /boot/efi/EFI/ZBM/VMLINUZ.EFI -L

Configure EFI boot entries#

mount -t efivarfs efivarfs /sys/firmware/efi/efivars
apt install efibootmgr
efibootmgr -c -d "$BOOT_DISK" -p "$BOOT_PART" \
  -L "ZFSBootMenu (Backup)" \

efibootmgr -c -d "$BOOT_DISK" -p "$BOOT_PART" \
  -L "ZFSBootMenu" \

See also

Some systems can have issues with EFI boot entries. If you reboot and do not see the above entries in your EFI selection screen (usually accessible through an F key during POST), you might need to use a well-known EFI file name. See Portable EFI for help with this. Your existing ESP can be used, in place of an external USB drive.

Refer to zbm-kcl.8 and zfsbootmenu.7 for details on configuring the boot-time behavior of ZFSBootMenu.

Prepare for first boot#

Exit the chroot, unmount everything#

umount -n -R /mnt

Export the zpool and reboot#

zpool export zroot