Why

I wanted to install a new arch linux configuration but using zfs as root file system, so that i can see if i can configure snapshots for updates. But i want to have as much as posible encrypted so, my setup will be

  • partition 1: efi partition, vfat unencrypted for /boot/efi
    • maybe secure it with secure boot
  • partition 2: luks 1 encrypted / ext4 formated for /boot and grub
    • luks v1 is needed because grub can’t open luks v2
  • partition 3: luks 2 encrpted / lvm with swap and zfs root filesystem
    • zfs can’t handle a swap file, so using lvm so that swap partition and zfsroot are encrypted
    • i want the swap partition encrypted so that i can have a encrypted suspend to disk

For who

For a advanced linux user

Step 1

Boot a ubuntu iso or usb, i am using ubuntu-24.04.2-desktop-amd64.iso (the arch installer iso doesn’t have zfs tools, so it is easier to use a ubuntu iso with all tooling) and configure and partitions and format them. Please remember i give examples for /dev/nvme0n1 or /dev/sda but use your disk and partitions like you have (check with fdisk -l)

  • Open a terminal and use sudo to become root
  • install some default packages
apt-get install -y arch-install-scripts vim rsync docker.io
  • Use gdisk to partition the file disk
gdisk /dev/sda
# or
gdisk /dev/nvme0n1
# or
gdisk /dev/<yuur disk>
  • Create a partition table like this
Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         1050623   512.0 MiB   EF00  EFI system partition
   2         1050624         3147775   1024.0 MiB  8309  Linux LUKS
   3         3147776        41940991   18.5 GiB    8309  Linux LUKS
  • How to use gdisk
    • use n to create a new partition
    • partition number 1, 2 and 3 (use default value)
    • first sector (use default value)
    • last sector (use +512m for first partition, +1024m for second partition and default for last partition), or use you’re own values
    • Hex Code, use EF00 (1 partition), 8309 (2 and 3 partition)
    • after creating 3 partition use w to write
  • format efi partition
mkfs.fat -F 32 /dev/sda1 -n ARCH2025ZFS
or
mkfs.fat -F 32 /dev/nvme0n1p1 -n ARCH2025ZFS
  • create luks for /boot parition and format /boot partition
# format cryptboot
cryptsetup luksFormat --type luks1 /dev/sda2
or
cryptsetup luksFormat --type luks1 /dev/nvme0n1p2

# open cryptboot
cryptsetup open /dev/nvme0n1p2 cryptboot
or
cryptsetup open /dev/sda2 cryptboot

# format 
mkfs.ext4 /dev/mapper/cryptboot
or
mkfs.btrfs /dev/mapper/cryptboot
  • crypte luks for zfsroot and create lvm
cryptsetup luksFormat /dev/sda3
or
cryptsetup luksFormat /dev/nvme0n1p3

# open cryptlvm
cryptsetup open /dev/sda3 cryptlvm
or
cryptsetup open /dev/nvme0n1p3 cryptlvm

# create lvm
# by restart   vgchange -a y
pvcreate /dev/mapper/cryptlvm
vgcreate arch2025 /dev/mapper/cryptlvm
  • create swap lvm and mkswap
lvcreate -L 8G arch2025 -n swap
mkswap /dev/mapper/arch2025-swap
  • create lvm root fs and create zfs pool
lvcreate -l 100%FREE arch2025 -n root

zpool create -f -o ashift=12           \
                -O acltype=posixacl       \
                -O relatime=on            \
                -O xattr=sa               \
                -O dnodesize=legacy       \
                -O normalization=formD    \
                -O mountpoint=none        \
                -O canmount=off           \
                -O devices=off            \
                -R /mnt                   \
                -O compression=lz4        \
                -O dedup=on               \
                rpool /dev/arch2025/root
  • set mountpoint and mount zfs
zfs create -o mountpoint=none rpool/arch2025
zfs create -o mountpoint=/ -o canmount=noauto rpool/arch2025/root

# finally export the zfs pool and import it again: https://forum.manjaro.org/t/howto-install-full-manjaro-on-zfs-filesystem/69168
zpool export rpool
zpool import -d /dev/arch2025/root -R /mnt rpool -N

zfs mount rpool/arch2025/root
  • check is rpoot is mount with df /mnt
  • mount boot en boot/efi
mkdir /mnt/boot
mount /dev/mapper/cryptboot /mnt/boot

# and boot/efi
mkdir /mnt/boot/efi

mount /dev/sda1 /mnt/boot/efi
or
mount /dev/nvme0n1p1 /mnt/boot/efi
  • check mounts
df | grep /mnt
rpool/arch2025/root    20315520     128  20315392   1% /mnt
/dev/mapper/cryptboot   1046528    5920    924544   1% /mnt/boot
/dev/sda1                523244       4    523240   1% /mnt/boot/efi
  • Export zpool.cache
zpool set bootfs=rpool/arch2025/root rpool
zpool set cachefile=/etc/zfs/zpool.cache rpool
mkdir -p /mnt/etc/zfs
cp /etc/zfs/zpool.cache /mnt/etc/zfs/zpool.cache

Step 2

Bootstrap arch linux using a docker arch container, i tried to install pacman and pacstrap in ubuntu in initialize the pacman key, but i managed to get it working once, but i got a lot of gpg checksum errors most of the time, so using docker seems the easiest way. We need to use the linux-lts kernel because it the time of writing kernel 6.13 didn’t have zfs support, you can offcourse change the packages that you need

  • start docker container
docker run --privileged --rm --name docker-arch -v /mnt:/mnt -h docker-arch -t -i archlinux:latest /bin/bash
  • in the docker container run the following command to boot strap arch linux
pacman -Sy --noconfirm arch-install-scripts rsync
pacstrap -K /mnt base linux-lts linux-firmware linux-lts-headers vim git base-devel plocate grub efibootmgr os-prober lvm2 wireless-regdb scx-scheds less git base-devel vim netctl git vim dialog networkmanager iwd modemmanager os-prober sudo alsa-utils efibootmgr refind openssh wget screen tmux syncthing
  • rsync the pacman conf in the container to the /mnt partition, offcourse you can change mirrors and config later on if needed
rsync -avP /etc/pacman.conf /mnt/etc/
rsync -avP /etc/pacman.d/ /mnt/etc/pacman.d/
  • exit docker with ctrl-d or exit
  • if you have added you’re private ssh key to the ubuntu live cd for easy acces, copy it to the arch install
rsync -avP /root/.ssh/ /mnt/root/.ssh/
  • chroot to the arch install in /mnt
arch-chroot /mnt
  • create a normal user in the chroot to do the yay install and zfs packages install i am using richard as the user, but you can choice you’re own name
useradd -G wheel -m richard
passwd richard
  • enable the wheel group to add root access using sudo
vim /etc/sudoers
# find and uncomment wheel group line in sudoers file and save with :wq!
  • edit the hook line in mkinitcpio.conf
vim /etc/mkinitcpio.conf
# find and change hooks file to
HOOKS=(base udev autodetect modconf kms block keyboard keymap encrypt lvm2 zfs resume filesystems fsck)
  • You need to know the uuid of you’re newly created partitions so store them somewhere
blkid /dev/sda1
or
blkid /dev/nvme0n1p1

UUID="xxxx-xxxx"   # check output of command

# Do the same for partition 2 and 3, there UUID wil be longer like
UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"   # for partition 2 and
UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"   # for partition 3
  • Create a cryptboot, using the value for partition 2 and partition 3
vim /etc/crypttab
# add the following lines
cryptboot     UUID=parition 2 uuid
cryptlvm      UUID=partition 3 uuid

# for me it is
cryptboot     UUID=cb96cf72-b5d8-43f1-b369-fb33a49fe8a0
cryptlvm      UUID=d368565b-1cb3-4cdc-a6b7-8e4e425ac511
  • Now we need to change /etc/default/grub we will need the value for uuid partition 3
vim /etc/default/grub
# change line: GRUB_CMDLINE_LINUX=""
GRUB_CMDLINE_LINUX="cryptdevice=/dev/disk/by-uuid/<UUID partition 3>:cryptlvm"

# for me it is
GRUB_CMDLINE_LINUX="cryptdevice=/dev/disk/by-uuid/d368565b-1cb3-4cdc-a6b7-8e4e425ac511:cryptlvm"

# enable the grub_enable_cryptodisk
enable the GRUB_ENABLE_CRYPTODISK=y in /etc/default/grub
  • update fstab and add partitions there, change uuid /boot/efi of course to you’re setup
vim /etc/fstab
# add lines
/dev/mapper/cryptboot /boot     auto    nofail,defaults,noatime 0       2
UUID=<uuid partition 1> /boot/efi        auto    defaults,noatime 0       2
/dev/mapper/arch2025-swap       none    swap    sw      0       0

# for me it is
/dev/mapper/cryptboot /boot     auto    nofail,defaults,noatime 0       2
UUID=4070-5871 /boot/efi        auto    defaults,noatime 0       2
/dev/mapper/arch2025-swap       none    swap    sw      0       0
  • install grub on root disk (if you are using refind, you can use –no-nvram to not update bios
grub-install /dev/sda
or
grub-install /dev/nvme0n1
or
grub-install --no-nvram /dev/sda
or
grub-install --no-nvram /dev/nvme0n1
  • Now you need to use the user that you created (for me richard)
su - richard
git clone https://aur.archlinux.org/yay.git
cd yay
makepkg --noconfirm -si
  • Install zfs-dkms and zfs-utils using yay
yay --noconfirm zfs
# install zfs-dkms and zfs-utils
  • Exit you’re user and return to root in you’re chroot
exit
  • No we are ready to create a grub config
grub-mkconfig -o /boot/grub/grub.cfg
  • change root password
passwd root
  • Enable some systemd services in you’re chroot
systemctl enable zfs.target
systemctl enable zfs-import-cache
systemctl enable zfs-mount
systemctl enable zfs-import.target
systemctl enable NetworkManager
systemctl enable sshd
  • Generate the hostid
zgenhostid $(hostid)
  • change hostname
vim /etc/hostname
  • And know umount and export rpool so that we are read
umount -a
exit # out of chroot
zfs unmount -a
zfs umount /mnt
# export rpool so that you can boot from it
zpool export rpool
  • Reboot in you’re new installation
shutdown -r now

Todo

  • create subvolumes zfs for /home etc.
  • create snapshot with pacman updates in zfs and btrfs boot
  • create grub boot options for older snapshots
  • give some tips to change the 3 times password prompts on boot to 2 or 1
    • prompt 1: grub unlocks /boot for grub.cfg and kernel and initramfs
    • prompt 2: unlock root fs luks file system
    • prompt 3: unlock /boot in lkernel boot