Arch Linux install on ZFS

Important

Please refer to the Arch Wiki for the official guide on how to install Arch Linux. These are my notes adapted from the Arch ZFS wiki

Download the latest archiso and boot to it.

Install the ZFS kernel modules

curl -s https://eoli3n.github.io/archzfs/init | sed 's- &>/dev/null--' | bash

Setup disk partitions

Note

In this guide we will be installing Arch Linux onto a root ZFS filesystem. To save some headache we won’t be using ZFS on our boot partition. We’ll be using GPT and UEFI as opposed to MBR. For the differences, please see this article

Using the parted utility let’s create our partitions

parted /dev/sda
(parted) mklabel gpt
(parted) mkpart non-fs 0% 200
(parted) mkpart parimary 200 100%
(parted) set 1 esp on
(parted) set 1 boot on

Or we can run this all as one command using the --script option

parted --script /dev/sda mklabel gpt mkpart non-fs 0% 200 mkpart primary 200 100% set 1 esp on set 1 boot on

Format our boot partition

mkfs.fat -F32 /dev/sda1

Create our zpool

Find the disk ID we’re going to be using for ZFS. You can find it by running ls /dev/disk/by-id

Warning

I’m using vmware and I couldn’t find anything listed in /dev/disk/by-id. I had to edit the settings of the VM to support it. In Edit Settings -> VM Options -> Advanced -> Edit Configuration add disk.EnableUUID TRUE

zpool create -f -o ashift=9 \
    -O acltype=posixacl \
    -O canmount=off \
    -O compression=lz4 \
    -O devices=off \
    -O dnodesize=legacy \
    -O mountpoint=none \
    -O normalization=formD \
    -O relatime=on \
    -O xattr=sa \
    -R /mnt \
    zroot /dev/disk/by-id/scsi-36000c29168cfcdb14fb4e851f81025cf-part2

Create our data sets

zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/default
zfs create -o mountpoint=none zroot/data
zfs create -o mountpoint=/home zroot/data/home
zfs create -o mountpoint=/root zroot/data/home/root
zfs create -o mountpoint=/var zroot/data/var
zfs create -o mountpoint=/var/log zroot/data/var/log
zfs create -o mountpoint=/tmp zroot/data/tmp

Export/import your datasets

To validate your configurations, export then reimport all your zpools.

Warning

Do not skip this, otherwise you will be required to use -f when importing your pools. This unloads the imported pool.

zpool export zroot; zpool import -d /dev/disk/by-id -R /mnt zroot -N

Remount your datasets:

zfs mount zroot/ROOT/default; zfs mount -a

Configure the root filesystem

Set the bootfs property on the descendant root filesystem so the boot loader knows where to find the operating system.

mkdir -p /mnt/etc/zfs; zpool set cachefile=/etc/zfs/zpool.cache zroot; cp /etc/zfs/zpool.cache /mnt/etc/zfs/zpool.cache

Mount the the boot partition inside /mnt/boot

mkdir /mnt/boot; mount /dev/sda1 /mnt/boot

genfstab -U -p /mnt >> /mnt/etc/fstab.zfs

Bootstrap your arch system

pacstrap /mnt base zfs-linux-lts vim

Create/enter the chroot

arch-chroot /mnt

Add the ZFS repo to pacman

cat << EOF >> /etc/pacman.conf
[archzfs]
Server = http://archzfs.com/archzfs/x86_64
Server = http://mirror.sum7.eu/archlinux/archzfs/archzfs/x86_64
Server = https://mirror.biocrafting.net/archlinux/archzfs/archzfs/x86_64
EOF

Some basic arch configs

Set local timezone and create /etc/adjtime

ln -sf /usr/share/zoneinfo/America/Los_Angeles /etc/localtime
hwclock --systohc

set and generate locale

echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf

Set the host name

hostnamectl set-hostname <hostname>

Adjust the hosts file

cat << EOF >> /etc/hosts
127.0.0.1    localhost.localdomain   localhost
::1          localhost6.localdomain   localhost6
192.168.1.250 $myhostname.$mydomain   $myhostname
2001:470:8050:1::250 $myhostname.$mydomain  $myhostname
EOF

Enable NTP daemon

timedatectl set-ntp true

Configure networking

DHCP

cat << EOF > /etc/systemd/network/eth0.network
[Match]
Name=eth0

[Network]
DHCP=yes
EOF

Static

cat << EOF > /etc/systemd/network/eth0.network
[Match]
Name=eth0

[Network]
Address=192.168.1.250/24
Gateway=192.168.1.1
DNS=192.168.1.53

Address=2001:470:8050:1::250/64
Gateway=2001:470:8050:1::1
DNS=2001:470:8050:1::53
EOF

Then enable networking at startup

systemctl enable systemd-networkd
systemctl enable systemd-resolved

Set the root password

passwd

Configure systemd-boot

mkdir -p /boot/loader/entries
cat << EOF > /boot/loader/loader.conf
default arch
console-mode max
timeout 5
EOF
cat << EOF > /boot/loader/entries/arch.conf
title Arch Linux
linux /vmlinuz-linux-lts
initrd /initramfs-linux-lts.img
options net.ifnames=0 zfs=zroot/ROOT/default rw
EOF
bootctl --path=/boot install

Configure systemd ZFS mounts

zpool set cachefile=/etc/zfs/zpool.cache zroot
systemctl enable zfs.target
systemctl enable zfs-import-cache
systemctl enable zfs-mount
systemctl enable zfs-import.target
rm /etc/hostid && zgenhostid $(hostid)

Update /etc/mkinitcpio.conf and regen the initrd

sed -i 's|^HOOKS.*|HOOKS=\"base udev autodetect modconf block keyboard zfs filesystems\"|g' /etc/mkinitcpio.conf
mkinitcpio -p linux-lts

Got swap?

zfs create -V 2G -b $(getconf PAGESIZE) \
    -o compression=lz4 \
    -o logbias=throughput \
    -o sync=always \
    -o primarycache=metadata \
    -o secondarycache=none \
    -o com.sun:auto-snapshot=false \
    zroot/swap
mkswap /dev/zvol/zroot/swap
swapon /dev/zvol/zroot/swap
echo "/dev/zvol/zroot/swap none swap discard 0 0" >> /etc/fstab

Lose the swap

swapoff /dev/zvol/zroot/swap
zfs destroy zroot/swap