ZFS/rootfs
For those looking to find general information on using ZFS on Linux then please see the ZFS page instead.
This article is focused on using ZFS as the rootfs on Gentoo and designed to be used with the Handbook. Over time more advanced setups will be added so please check the TODO section to see if there is something that can be added to improve this article.
Partitions
Layout
Follow the Handbook section on Preparing the disks returning at the creating file systems section.
This guide will be using the example below however it should be simple enough to adapt this to the user's needs.
/dev/sda1 | 1024 MiB | EFI System Partition | /efi /dev/sda2 | 2048 MiB | swap | swap /dev/sda3 | Rest of Disk | ZFS Partition | /, /boot, /home, ...
Boot
Create a 1GB FAT32 filesystem:
root #mkfs.vfat -F 32 /dev/sda1Swap
Swap performance on a ZFS partition is known to be poor and using a swapfile is not supported, instead it is recommended to use its own partition.
root #mkswap /dev/sda2root #swapon /dev/sda2Alternatively, zram could be used on systems with a large amount of RAM but do note ZFS will cache data to RAM for speed.
ZFS Setup
Generate host ID
Randomly generate host ID into /etc/hostid allowing output overwrite.
root #zgenhostid -fAlternatively, set a specific host ID, 0x00bab10c in this example.
root #zgenhostid -f 0x00bab10cCreate a ZFS pool
Load ZFS kernel module and create a ZFS pool tank on /dev/sda3.
root #modprobe zfsroot #zpool create -f \
-o ashift=12 \
-o autotrim=on \
-o compatibility=grub2 \
-O acltype=posixacl \
-O xattr=sa \
-O relatime=on \
-O compression=lz4 \
-m none tank /dev/sda3The option
-o compatibility=grub2 makes sure that GRUB works. If you are using ZFSBootMenu, you can skip that option.Use
-o ashift=9 for disks with a 512 byte physical sector size or -o ashift=12 for disks with a 4096 byte physical sector size.
See OpenZFS: ashift property definition Alternative: Create a ZFS pool with LUKS encryption
Using LUKS involves creating an encrypted container on the physical partition first, then placing the ZFS pool inside that container.
Prepare the encrypted partition
First, initialize the physical partition (e.g., /dev/sda3) with LUKS. You will be prompted to set a password.
root #cryptsetup luksFormat /dev/sda3Open the encrypted device. This creates a virtual block device at /dev/mapper/cryptroot.
root #cryptsetup luksOpen /dev/sda3 cryptrootCreate the ZFS pool on LUKS
Now, create the pool using the mapper device instead of the raw partition.
root #modprobe zfsroot #zpool create -f \
-o ashift=12 \
-o autotrim=on \
-o compatibility=grub2 \
-O acltype=posixacl \
-O xattr=sa \
-O relatime=on \
-O compression=lz4 \
-m none tank /dev/mapper/cryptrootAfter this, proceed to Create ZFS file systems as usual. Note that you will need to unlock this partition every time you import the pool manually.
Update Dracut and Bootloader
For the system to boot, the initramfs must know how to unlock the LUKS device.
1. Find the UUID of your physical partition (e.g., /dev/sda3):
root #blkid /dev/sda32. Add the crypt module to your Dracut configuration in /etc/dracut.conf.d/zol.conf:
/etc/dracut.conf.d/zol.confDracut config for LUKS + ZFSnofsck="yes"
add_dracutmodules+=" zfs crypt "
3. Add the LUKS UUID to your kernel command line. For GRUB, edit /etc/default/grub:
/etc/default/grubKernel parameters for unlocking LUKSGRUB_CMDLINE_LINUX="rd.luks.uuid=YOUR-UUID-HERE"
Replace YOUR-UUID-HERE with the UUID from the blkid command. Finally, rebuild your initramfs and update your bootloader configuration.
Check that you have the
sys-fs/cryptsetup package installed in your world set before rebooting, as it's required for the initramfs to handle the LUKS container.Alternative: Create a ZFS pool with native encryption
Native encryption *used* to be unmaintained, but as of 2025 that is not the case anymore, see https://github.com/openzfs/zfs/issues/12014 https://github.com/openzfs/openzfs-docs/issues/494.
Native ZFS encryption can also be used by adding additional options when creating our zpool.
root #zpool create -f \
-o ashift=12 \
-o autotrim=on \
-o compatibility=openzfs-2.1-linux \
-O acltype=posixacl \
-O xattr=sa \
-O relatime=on \
-O compression=lz4 \
-O encryption=aes-256-gcm \
-O keylocation=prompt \
-O keyformat=passphrase \
-m none tank /dev/sda3It's also possible to set the keylocation property to point to a file, which is useful when using ZFSBootMenu as a bootloader, or when trying to reduce the number of passphrase prompts during boot. See the ZFSBootMenu documentation for more info on how it handles encrypted filesystems.
Create ZFS file systems
This guide will be only creating root and home file systems. However, the user is free to create additional file systems if desired.
root #zfs create -o mountpoint=none tank/osroot #zfs create -o mountpoint=/ -o canmount=noauto tank/os/gentooroot #zfs create -o mountpoint=/home tank/homeThe property
canmount=noauto should be set on any file systems with the root mountpoint. Omitting it can result in OS trying to automatically mount several file systems at / and failing.
/usr, /etc or any other system-critical folder on a different dataset, note that it has to be a child of the root dataset (e.g. tank/os/gentoo/usr), with canmount=on to be properly mounted by dracut-generated initramfsSet the preferred boot file system of the pool.
root #zpool set bootfs=tank/os/gentoo tankExport and re-import a pool, mount file systems
To export and re-import a pool with a specified mountpoint and without automatically mounting the file systems, run the following commands.
root #zpool export tankroot #zpool import -N -R /mnt/gentoo tankIt is then possible to mount root and home file systems.
If you used native encryption, load zfs key with
zfs load-key tankroot #zfs mount tank/os/gentooroot #zfs mount tank/homeIf you followed the example you can also mount your efi partition.
root #mount --mkdir /dev/sda1 /mnt/gentoo/efiAfter mounting the file systems, it is advisable to verify mountpoints by checking the output of the command below.
root #mount -t zfsHere is an example of the command output in case of successful mounting of file systems.
tank/os/gentoo /mnt/gentoo type zfs (rw,relatime,xattr,posixacl) tank/home on /mnt/gentoo/home type zfs (rw,relatime,xattr,posixacl)
Update device symbolic links:
root #udevadm triggerReturn to the Handbook - EFI_system_partition_filesyste and return just before entering chroot command.
Copy host ID file
root #cp /etc/hostid /mnt/gentoo/etcReturn to Handbook - Installing Gentoo base system and return here at Kernel configuration and compilation.
Kernel
The user can choose between manually configured kernel or the distribution kernel.
Distribution kernel
Enabling USE flag
If using the distribution kernel then the dist-kernel USE flag will need to be enabled:
/etc/portage/make.confEnabling dist-kernel USE flag in make.confUSE="dist-kernel"
Installing distribution kernel
root #emerge -av sys-kernel/gentoo-kernelOr, if you prefer using the pre-compiled binary,
root #emerge -av sys-kernel/gentoo-kernel-binManual kernel config
configure the kernel as desired, save and build ( do not install yet )
root #make -j$(nproc) && make modules_installinstall the zfs package ( if a kernel version error appears use the previous version )
root #emerge --ask zfsthen add zfs kernel module in dracut as shown previusly also write root=ZFS=tank/os/gentoo to /etc/cmdline or the initramfs will refuse to build now build and install, use installkernel for simplicity sake ( dracut and grub use flags enabled )
root #make -j$(nproc) && make modules_install && make installeverytime the gentoo-sources are emerged or the kernel config is changed you have to repeat this or it won't boot
ZFS userland utilities and kernel module
The sys-fs/zfs package is necessary to allow your system to interact with and manage your ZFS pools. Make sure the module flag is set
root #emerge -av sys-fs/zfs
Initramfs
Configure Dracut
Create a directory for Dracut configuration files if it does not exist.
root #mkdir -p /etc/dracut.conf.dThen, create a file zol.conf with the following content in this directory:
root #nano /etc/dracut.conf.d/zol.conf/etc/dracut.conf.d/zol.confDracut configuration for ZFSnofsck="yes"
add_dracutmodules+=" zfs "
Build the initramfs for the distribution kernel
root #emerge --config sys-kernel/gentoo-kernelOr, if the binary version was installed,
root #emerge --config sys-kernel/gentoo-kernel-binYou can return to the Handbook - Configuring the system and return here at Configuring the bootloader.
Bootloader
ZFSBootMenu
An overview of the ZFSBootMenu installation is given here, but a more in depth guide can be found at ZFS/ZFSBootMenu
Setting kernel command-line
root #zfs set org.zfsbootmenu:commandline="quiet loglevel=4" tank/osZFS properties are inherited, therefore all children datasets of
tank/os will inherit the command-line arguments. If necessary, the property can be overridden in specific child datasets.Mounting the EFI System Partition
The ZFSBootMenu documentation states that the kernel and initramfs must be located in the /boot directory of the ZFS root. However, the systemd installkernel will attempt to locate the mountpoint of your EFI partition and install the kernel-initramfs pair there instead, which in our case, is /efi Therefore, the
-systemd USE flag must be added to sys-kernel/installkernel to prevent that from happening.If the ESP was not mounted previously, it is necessary to do it now:
root #mkdir -p /efiroot #mount /dev/sda1 /efiInstalling ZFSBootMenu (from source)
ZFSBootMenu ebuild is available in the GURU repository, which has to be added first, if not done already:
root #emerge app-eselect/eselect-repositoryroot #eselect repository enable gururoot #emerge --syncThe package then needs to be unmasked.
/etc/portage/package.accept_keywords/zfsbootmenuUnmasking zfsbootmenu for installationsys-boot/zfsbootmenu ~amd64
sys-boot/zfsbootmenu can then be installed.
root #emerge --ask --verbose sys-boot/zfsbootmenuAfter that, the ZFSBootMenu configuration needs to be adjusted in order to:
- Enable automatic management of images: ManageImages:true
- Point to the EFI mount point: BootMountPoint: /efi
- Enable EFI binary generation: Enabled: true in the EFI section
/etc/zfsbootmenu/config.yamlZFSBootMenu configurationGlobal:
ManageImages: true
BootMountPoint: /efi
DracutConfDir: /etc/zfsbootmenu/dracut.conf.d
PreHooksDir: /etc/zfsbootmenu/generate-zbm.pre.d
PostHooksDir: /etc/zfsbootmenu/generate-zbm.post.d
InitCPIOConfig: /etc/zfsbootmenu/mkinitcpio.conf
Components:
ImageDir: /efi/EFI/BOOT
Versions: 3
Enabled: true
EFI:
ImageDir: /efi/EFI/BOOT
Stub: /usr/lib/systemd/boot/efi/linuxx64.efi.stub
Versions: false
Enabled: true
Kernel:
CommandLine: ro loglevel=0
Then the bootloader image needs to be generated:
root #generate-zbmThis will output an EFI image to /efi/EFI/BOOT/vmlinuz.EFI, which can then be copied to /efi/EFI/BOOT/BOOTX64.EFI, or sys-boot/efibootmgr can be used.
root #efibootmgr -c -d /dev/sdX -p 1 -L "ZFSBootMenu" -l '\EFI\BOOT\VMLINUZ.EFI'Installing ZFSBootMenu (prebuilt)
Create a directory for the bootloader and download the EFI binary into it.
root #mkdir -p /efi/EFI/BOOTroot #wget -L https://get.zfsbootmenu.org/latest.EFI -O /efi/EFI/BOOT/BOOTX64.EFICreating an EFI boot entry
Install the package sys-boot/efibootmgr.
root #emerge -av sys-boot/efibootmgrThen, an EFI boot entry can be created with the following command, if ZFSBootMenu was built from source:
root #efibootmgr -c -d /dev/sda -p 1 -L "ZFSBootMenu" -l \\EFI\\ZBM\\VMLINUZ.EFIOtherwise, in case the prebuilt ZFSBootMenu binary is used:
root #efibootmgr -c -d /dev/sda -p 1 -L "ZFSBootMenu" -l \\EFI\\BOOT\\BOOTX64.EFIOptional: Native Encryption
If you've opted for native encryption when you set up your zpool as described in Alternative: Create a ZFS pool with native encryption, it is possible to set up ZFSBootMenu to prompt for the passphrase once and have dracut have access to encryption keys at boot, or alternatively by setting the org.zfsbootmenu:keysource attribute and storing encryption keys on a separate dataset.
See the ZFSBootMenu documentation for info on how to properly set this up.
Limine
Limine is a modern, advanced, portable, multiprotocol bootloader and boot manager which also provides the reference implementation of the Limine boot protocol.
Follow the Limine article and making sure to follow the Limine#Using_Limine_With_ZFS_Root section.
Grand Unified Bootloader (GRUB)
Enable ZFS support for GRUB
Set the libzfs flag on the sys-boot/grub package to enable support for ZFS (by building sys-fs/zfs and sys-fs/zfs-kmod):
root #echo "sys-boot/grub libzfs" >> /etc/portage/package.use/grubBuild GRUB with ZFS support
Ensure the GRUB_PLATFORMS setting is properly configured for systems with EFI partition
root #echo 'GRUB_PLATFORMS="efi-64"' >> /etc/portage/make.confBuild the sys-boot/grub package:
root #emerge --ask sys-boot/grubInstall GRUB to mounted EFI partition
root #grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=gentooroot #grub-mkconfig -o /boot/grub/grub.cfgAdd CMDLINE for first boot only
root #nano /etc/default/grubroot #GRUB_CMDLINE_LINUX="refresh"execute "grub-mkconfig -o /boot/grub/grub.cfg" and when booting into gentoo remove it and reconfigure grub again with the command above
Finalize setup
Add the zfs-import and zfs-mount to boot service, otherwise the system will not boot.
OpenRC
root #rc-update add zfs-import sysinit && rc-update add zfs-mount sysinitRebooting the system
Exit the chrooted environment and unmount all mounted partitions, do not forget to export the pool. After that, the system can be rebooted.
root #exitroot #cdroot #umount -l /mnt/gentoo/dev{/shm,/pts,}root #umount -n -R /mnt/gentooroot #zpool export tankroot #reboot
Gentoo doesn't boot after reboot
Press E key in the grub entry and add "refresh" to the cmdline
TODO
Sections needed to be added for a more complete guide
- Add instructions for alternative bootloaders
- Add instructions for ZFSBootMenu installation via
generate-zbm(likely requires using GURU)