A complete guide to install Arch Linux on ZFS, "The last word in filesystems", step by step.
Introduction
In summary, ZFS is a stable, fast and advanced filesystem with many features such as snapshotting, native encryption and caching in memory. In this post we'll go through the complete process of installing Arch Linux on ZFS, starting with creating a bootable USB drive with ZFS support.
Building an Arch ISO with ZFS support
The default ISO image you can download from the Arch Linux website does not support ZFS.
That's why we have to create our own using the archiso
tool. We will install the tool from
the Arch Linux repositories.
docker run --rm --privileged -it -v "$(pwd)/out":/root/iso/out archlinux
- Install the
archiso
tool, create a work directory and copy the releng profile to it.
sudo pacman -Sy archiso
mkdir ~/iso
cp -r /usr/share/archiso/configs/releng/* ~/iso
- Add the ArchZFS repository to the Pacman configuration for our build and tell
archiso
to install the ZFS DKMS module and ZFS utils to our resulting ISO.
echo -e '
[archzfs]
Server = https://archzfs.com/$repo/$arch
SigLevel = Optional TrustAll' >> ~/iso/pacman.conf
echo -e '
linux-headers
archzfs-dkms
zfs-utils' >> ~/iso/packages.x86_64
- Next, build the ISO. This can take some time…
sudo mkarchiso -vo ~/iso/out ~/iso
- Finally, write the ISO to a USB drive using your favorite tool, restart your computer and boot it.
Storage setup
Partitioning
Before getting started, I set my keymap and make the console font larger.
loadkeys de-latin1
setfont ter-132n
Once everything is set up, start parted
on the drive you want to install
Arch Linux to (/dev/nvme0n1
in my case) and create a new GPT partition table and partitions.
Though it's not covered in this post, it should be no problem to install Arch Linux on ZFS
alongside existing operating systems. If you want to do this, skip creating a new partition table
and partition the disk to your liking.
parted -a opt /dev/nvme0n1
print # Display current partition table
mklabel gpt # Create new partition table, will destroy data!
mkpart primary 5MB% 512MB # Boot/EFI
mkpart primary 512MB 100% # remaining space
set 1 boot on # Boot flag
set 1 esp on # EFI flag
quit
Creating the ZFS Pool
Let's create a new ZFS pool named "zroot". The options are a solid
default for a pool for day to day desktop use. We'll build our final root filesystem in /mnt
, so
/mnt
in the installer OS will be /
in the installed system.
Make sure to match the capitalization of the o/O
letters!
zpool create \
-o ashift=12 \
-O acltype=posixacl -O canmount=off \
-O dnodesize=auto -O normalization=formD \
-O atime=off -O xattr=sa -O mountpoint=none \
-R /mnt zroot /dev/nvme0n1p2 # ← Partition 2
Creating datasets
You need at least one dataset for your root filesystem /
. I'm creating an
additional dataset for my /home
directory, so I can take snapshots of my base
system and it separately. You can create additional datasets if you want.
# Root dataset
zfs create -o canmount=noauto -o mountpoint=/ zroot/rootfs
# Set the root dataset as bootfs
zpool set bootfs=zroot/rootfs zroot
# Additional datasets…
zfs create zroot/rootfs/home
Next, mount the root dataset. This will also mount any child datasets you created.
zfs mount zroot/rootfs
Finally, we need to tell ZFS to create a zpool.cache
file. This file contains information
about out ZFS pool and can be loaded at boot time instead of re-importing the pool each time.
Because /etc/zfs
is part of the installer, we have to copy the cache file to our soon-to-be
/etc/zfs
in /mnt
.
mkdir -p /mnt/etc/zfs
zpool set cachefile=/etc/zfs/zpool.cache zroot
cp /etc/zfs/zpool.cache /mnt/etc/zfs/zpool.cache
Setting up the boot partition
Format the boot partition with FAT32 and mount it into /mnt/boot
.
mkfs.vfat /dev/nvme0n1p1
mkdir /mnt/boot
mount /dev/nvme0n1p1 /mnt/boot
Generate filesystem table
Now that all filesystems for the new Arch installation are mounted in /mnt
,
we can generate the final fstab
using the genfstab
tool.
genfstab -U -p /mnt >> /mnt/etc/fstab
System setup
Install base packages
Use pacstrap
to install the base packages and a desktop environment. You can pick another
desktop environment or shell and leave out SSH or ZSH if you want to.
pacstrap /mnt base base-devel linux linux-headers linux-firmware grub efibootmgr \
nano zsh gdm gnome openssh
Setup ZFS
After chrooting into your new system, the first thing to do is to add the ArchZFS repository and install the ZFS DKMS module. After that, you can install additional packages you want in your new system.
arch-chroot /mnt
echo -e '
[archzfs]
Server = https://archzfs.com/$repo/x86_64' >> /etc/pacman.conf
# ArchZFS GPG keys (see https://wiki.archlinux.org/index.php/Unofficial_user_repositories#archzfs)
pacman-key -r DDF7DB817396A49B2A2723F7403BD972F75D9D76
pacman-key --lsign-key DDF7DB817396A49B2A2723F7403BD972F75D9D76
pacman -Sy zfs-dkms
# Optional packages
pacman -S nvidia-dkms intel-ucode
Boot setup
Edit /etc/mkinitcpio.conf
, find the line that defines build hooks (HOOKS=(...)
) and add the ZFS hooks
like this:
HOOKS=(base udev autodetect modconf block keyboard keymap zfs filesystems)
After that, generate the image with
mkinitcpio -p linux
Finally, let's set up GRUB. First, make sure to create the /boot/grub
directory.
Edit the file /etc/default/grub
and add zfs=zroot/rootfs
to the kernel parameters
at GRUB_CMDLINE_LINUX_DEFAULT
. Generate the GRUB configuration files and install
GRUB with the according tools:
mkdir /boot/grub
nano /etc/default/grub # GRUB_CMDLINE_LINUX_DEFAULT="zfs=zroot/rootfs"
grub-mkconfig -o /boot/grub/grub.cfg
grub-install --target=x86_64-efi --efi-directory=/boot
Finalizing the installation
We need to enable some services for systemd to be able to handle and mount our ZFS datasets.
Remember to enable your display manager service, too (gdm
in my case).
systemctl enable zfs.target zfs-import-cache \
zfs-mount zfs-import.target gdm
The following are some common tasks like setting the correct timezone, locale, hostname,
creating a new user and enable the use of sudo
.
# Set time and timezone
ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime # Change according to location…
hwclock --systohc # Sync with HW clock
# Configure locales
echo -e '
de_DE.UTF-8 UTF-8
en_US.UTF-8 UTF-8' >> /etc/locale.gen
echo 'KEYMAP=de-latin1' > /etc/vconsole.conf
echo 'LANG=de_DE.UTF-8' > /etc/locale.conf
locale-gen
# Set hostname
echo myhostname > /etc/hostname
echo -e '127.0.0.1 localhost\n::1 localhost\n127.0.1.1 myhostname' >> /etc/hosts
groupadd sudo
useradd -m -G sudo <username>
EDITOR=nano visudo # uncomment sudo group
passwd <username>
You're done! Exit the chroot with exit
, unmount all filesystems, export the ZFS pool and reboot
into your new OS!
exit
# Back in the installer shell…
umount -R /mnt
zfs umount -a
zpool export -a
Changelog
- Mar 23, 2021: Import and verify against ArchZFS keys in final installation
- Jul 26, 2021: Set the
bootfs
separately after creating the pool and root dataset, as it doesn't seem to work (anymore?) during zpool creation. - Jul 27, 2021: Remove NetworkManager as required service (you can still install and enable it if you want to use it)