5 minutes
Debian 13 with Encrypted ZFS Root (ZFS on LUKS)
A step-by-step recipe for installing Debian 13 (Trixie) with a fully encrypted root filesystem using ZFS on top of LUKS.
Disclaimer: This process will nuke all data on the drives you target. Back up anything you want to keep before you start.
This gives you the integrity and snapshot features of ZFS, with the whole disk encrypted at rest. I use this on my home servers and VPS instances.
Prerequisites
- Debian 13 Live ISO (the standard live image, not the netinst)
- Two disks for a mirror, or one disk if you are starting small
- UEFI boot (recommended for modern systems)
Why not just ZFS native encryption?
ZFS native encryption (zencrypt) exists and works. But LUKS gives you a battle-tested crypto layer that GRUB, initramfs, and every Linux tool understand natively. Combined with ZFS on top, you get the best of both worlds.
Step 1: Boot and prepare
Boot from the Debian 13 Live ISO and open a terminal.
sudo -i
Enable contrib and non-free for ZFS:
echo "deb http://deb.debian.org/debian trixie main contrib non-free non-free-firmware" > /etc/apt/sources.list
apt update
Install the essentials:
apt install --yes debootstrap gdisk sgdisk cryptsetup \
zfs-dkms zfs-initramfs linux-headers-$(uname -r)
Load the ZFS module:
modprobe zfs
Step 2: Partition the disks
Clear any existing partition tables:
# Replace sdX and sdY with your disk IDs
sgdisk --zap-all /dev/sdX
sgdisk --zap-all /dev/sdY
Create the partitions on each disk. I will use sdX as the placeholder — repeat every command for sdY.
EFI partition (UEFI systems):
sgdisk -n1:1M:+512M -t1:EF00 /dev/sdX
Boot partition (unencrypted, for GRUB):
sgdisk -n2:0:+1G -t2:8300 /dev/sdX
LUKS data partition (rest of the disk):
sgdisk -n3:0:0 -t3:8300 /dev/sdX
Verify with:
sgdisk -p /dev/sdX
You should see three partitions: an EFI, a 1 GB boot, and a data partition filling the rest.
Step 3: Format the EFI and boot partitions
mkfs.fat -F32 /dev/sdX1
mkfs.fat -F32 /dev/sdY1
mkfs.ext4 /dev/sdX2
mkfs.ext4 /dev/sdY2
Step 4: Create the encrypted LUKS partition
Use aes-xts-plain64 with a 512-bit key on the third partition of each disk:
cryptsetup --cipher aes-xts-plain64 --key-size 512 \
--verify-passphrase --hash sha512 --use-random \
luksFormat /dev/sdX3
cryptsetup --cipher aes-xts-plain64 --key-size 512 \
--verify-passphrase --hash sha512 --use-random \
luksFormat /dev/sdY3
Open and map the encrypted devices:
cryptsetup luksOpen /dev/sdX3 root_crypt1
cryptsetup luksOpen /dev/sdY3 root_crypt2
Step 5: Create the ZFS pool
Create a mirrored ZFS pool on the mapped LUKS devices:
zpool create -o ashift=12 \
-O atime=off -O canmount=off -O compression=lz4 \
-O normalization=formD -O xattr=sa \
-O mountpoint=/ -R /mnt \
rpool mirror \
/dev/disk/by-id/dm-name-root_crypt1 \
/dev/disk/by-id/dm-name-root_crypt2
If using a single disk:
zpool create -o ashift=12 \
-O atime=off -O canmount=off -O compression=lz4 \
-O normalization=formD -O xattr=sa \
-O mountpoint=/ -R /mnt \
rpool /dev/disk/by-id/dm-name-root_crypt1
Step 6: Create ZFS datasets
# Container for root filesystem snapshots
zfs create -o canmount=off -o mountpoint=none rpool/ROOT
zfs create -o canmount=noauto -o mountpoint=/ rpool/ROOT/debian
zfs mount rpool/ROOT/debian
zpool set bootfs=rpool/ROOT/debian rpool
# User data
zfs create -o setuid=off rpool/home
zfs create -o mountpoint=/root rpool/home/root
# System datasets
zfs create -o canmount=off -o setuid=off -o exec=off rpool/var
zfs create -o com.sun:auto-snapshot=false rpool/var/cache
zfs create rpool/var/log
zfs create rpool/var/spool
zfs create -o com.sun:auto-snapshot=false -o exec=on rpool/var/tmp
# Separate /tmp dataset
zfs create -o com.sun:auto-snapshot=false -o setuid=off rpool/tmp
chmod 1777 /mnt/tmp
Step 7: Install the base system
debootstrap trixie /mnt
Mount the boot partition and virtual filesystems:
mkdir /mnt/boot
mount /dev/sdX2 /mnt/boot
mount --rbind /dev /mnt/dev
mount --rbind /proc /mnt/proc
mount --rbind /sys /mnt/sys
chroot /mnt /bin/bash --login
Step 8: Configure the installed system
Inside the chroot, mount /tmp and set up fstab:
mount /tmp
ln -s /proc/self/mounts /etc/mtab
Create /etc/fstab:
rpool/ROOT/debian / zfs defaults,noatime 0 0
/dev/sdX2 /boot ext4 defaults 0 0
/dev/sdX1 /boot/efi vfat defaults 0 0
tmpfs /tmp tmpfs nosuid,nodev 0 0
Set up networking, hostname, and locales:
echo "deb http://deb.debian.org/debian trixie main contrib non-free non-free-firmware" > /etc/apt/sources.list
apt update
apt install --yes linux-image-amd64 grub-efi zfs-initramfs cryptsetup locales
dpkg-reconfigure locales # ensure en_US.UTF-8 is selected
dpkg-reconfigure tzdata
Configure cryptsetup initramfs hook:
sed -i 's/#CRYPTSETUP=y/CRYPTSETUP=y/' /etc/cryptsetup-initramfs/conf-hook
Add the encrypted devices to crypttab:
echo "root_crypt1 /dev/disk/by-id/ata-YOURDISK-part3 none luks,discard" >> /etc/crypttab
echo "root_crypt2 /dev/disk/by-id/ata-YOURDISK-part3 none luks,discard" >> /etc/crypttab
Step 9: Install GRUB
# Enable GRUB to find ZFS
echo GRUB_PRELOAD_MODULES="part_gpt zfs" >> /etc/default/grub
echo GRUB_DISABLE_OS_PROBER=true >> /etc/default/grub
# Ensure ZFS pool devices are found by their /dev/disk/by-id names
echo "export ZPOOL_VDEV_NAME_PATH=YES" > /etc/profile.d/zpool_vdev_name.sh
ZPOOL_VDEV_NAME_PATH=YES update-grub
update-initramfs -u -k all
# Install to both disks for redundancy
grub-install /dev/sdX
grub-install /dev/sdY
Step 10: Exit and reboot
exit # exit chroot
umount -R /mnt
zpool export rpool
cryptsetup luksClose root_crypt1
cryptsetup luksClose root_crypt2
reboot
On first boot, you will be prompted for the LUKS passphrase. After that, ZFS imports automatically and the system boots.
Next up: automatic unlock at boot
Typing a passphrase every time a server reboots gets old fast. See the next recipe to configure Tang + Clevis for password-less boot.
Credits and sources
This recipe builds on knowledge from several older guides that are still relevant:
- Fully encrypted ZFS root on Linux using LUKS by Koen Diels
- Setup encrypted Ubuntu with ZFS on LUKS by morph027
- Debian Stretch Root on ZFS — ZFS on Linux wiki
- Installing Debian with root on encrypted ZFS mirror — Tech or T