Installing Ubuntu 23.10 with ZFS on root and ZFSBootManager

Lately, I had to reinstall my laptop and a few virtual machines. In the past, I tested BTRfs, but I had too many issues with it, so my go-to filesystem reverted to ZFS, which I’ve been using for years.

Usually, I would install my Ubuntu-based machines following the directions from OpenZFS. However, such an approach is a bit overwhelming, it’s a bit outdated as it still only have the latest LTS version, while I’m running on the latest 23.10.

To make things more interesting, I had two laptops that decided they would not boot anymore via GRUB into my ZFS-on-root Ubuntu in the past month. The cause is, apparently, a known one (sorry, I did not keep the reference) and one that is not easy to fix. I, therefore, decided to move to ZFSBootMenu(ZBM) as my boot loader and, as I have a multiboot environment, I’m using rEFInd to have a decent graphical interface at boot phase.

Installing Ubuntu 23.10 with ZFS on root and ZFSBootMenu

The installation of Ubuntu with ZFSBootMenu is slightly different from the one described in the official ZFS for Linux wiki, mainly as a single dataset is used.

I will not go through the single steps as you can quickly look them up directly on ZFSBootMenu website.

The differences

Here, I will discuss what I did differently from the approach from ZFSBootMenu.

  1. First, ZBM’s instructions only set up an EFI partition and a ZFS one. I use a swap partition as well.
  2. Second, my primary laptop is, unfortunately, equipped with a wifi card with bad drivers (RTL8821CE) and requires specific steps to get the working one onboard.
  3. Third, I often do tests on virtual machines, so I needed to automate the installation; hence, I created a script which is available on GitHub.
  4. I want all my machines to use ZFS’ native encryption so everything done in the process is aligned with those steps.
  5. Lastly, rEFInd. Why? Because it’s straightforward to configure, it provides an excellent graphical interface and makes my life easier.

What the script does

My script automates all the steps required, so instead of describing the commands line by line, which would be a repetition of the ZBM documentation, I’ll comment what my script does.

At the very beginning there are a bunch of variables to set-up

######################## 
# Change ${RUN} to true to execute the
script RUN="false"

# Variables - Populate/tweak this before launching the script 
export DISTRO="desktop" #server, desktop export RELEASE="mantic" # The short name of the release as it appears in the repository (mantic, jammy, etc) 
export DISK="sda" # Enter the disk name only (sda, sdb, nvme1, etc) 
export PASSPHRASE="SomeRandomKey" # Encryption passphrase for "${POOLNAME}" 
export PASSWORD="mypassword" # temporary root password & password for ${USERNAME}
export HOSTNAME="myhost" # hostname of the new machine 
export USERNAME="myuser" # user to create in the new machine 
export MOUNTPOINT="/mnt"# debootstrap target location 
export LOCALE="en_US.UTF-8" # New install language setting.  
export TIMEZONE="Europe/Rome" # New install timezone setting.  
export RTL8821CE="false" # Download and install RTL8821CE drivers as the default ones are faulty

## Auto-reboot at the end of installation? (true/false) 
REBOOT="false"
######################################################################## ###
Enable/disable debug. Only used during the development phase.

DEBUG="false" 

They are all documented and, hopefully, self-explanatory. 

The PASSWORD and PASSPHRASE variables are in plain text, so, in theory, they pose a security risk. You are exposed to this risk only during the installation while in front of your computer. Once the installation is completed and you reboot the machine, these files are gone as they only live at runtime when you boot from your USB key (see GitHub for all the installation steps)

Once you have set your variables, you just run the script (as root) and the following happens:

  • The script calculates the size of the swap partition to be equal to your physical memory (just in case you want to enable hibernation later)
  • The disk that you selected gets initialized and partitioned.
  • The ZFS pool gets created.
  • debootstrap is executed to install the base system in your target disk.
  • The swap partition is initialized (encrypted).
  • ZBM is installed and added to the EFI menu (yes, this last part is redundant as in the next step, rEFInd is installed, but I prefer a backup option in case it’s needed).
  • rEFIind is installed, and the default dark theme is downloaded and installed.
  • Now the required groups and basic network configurations are created.
  • Your user is created.
  • The Ubuntu flavour you selected is installed (server/desktop)
  • Compression of the logs is disabled as we already use compression at the ZFS pool level.
  • If selected, rtl8821ce drivers are downloaded and installed.
  • If enabled, the system automatically reboots (otherwise, you need to reboot manually)

That’s it; there you have your ZFS-on-root Ubuntu system.

P.S. I tested this with Ubuntu 23.04 and 23.10.

Diego Zaccariotto
Diego Zaccariotto
Head of Customer Support - Team Leader EMEA | Service Operations Management, Change & Transformation

I’m a Senior Manager and IT professional with 25+ years of experience, a background in system administration, and an MBA.