Prepare Installation Media
Grab the latest Arch ISO and write it to a USB.
Linux
Use dd. It’s simple:
sudo dd if=<Path to ISO> of=<Target Device> bs=4096 status=progress
Example:
sudo dd if=./archlinux-2021.07.01-x86_64.iso of=/dev/sdb bs=4096 status=progress
Windows
Use Etcher. Download it, run as administrator, pick your ISO and target drive. Done.
Boot from the newly created Arch install media.
Prepare Installation Environment
Set Mirrors
Once you’re in the live environment, rank the mirrors. This picks the fastest ones for you:
reflector --latest 20 --protocol https --sort rate --save /etc/pacman.d/mirrorlist
Then refresh the package database:
pacman -Syy
Load ZFS Modules
The live ISO doesn’t ship with ZFS modules, so we need to load them. eoli3n has a script that handles this automatically:
curl https://eoli3n.github.io/archzfs/init | bash
Configure Disks
Create Partitions
GRUB can’t boot from an encrypted boot partition, so we need a separate unencrypted /boot using something like ext4.
Set up a GPT partition table. Check the Arch Partitioning Guide if you need more detail. Your partitions should look roughly like this:
| Part | Size | Type |
|---|---|---|
| 1 | 100M | EFI boot partition (ef00) |
| 2 | 500M | Linux Filesystem |
| 3 | XXXG | Solaris Root (bf00) |
I’ll assume the disk is sda. So the EFI partition would be /dev/sda1.
Create ZFS Pool
A ZFS pool can span a single partition or multiple disks in RAID. Check the official docs for custom configs. We’re keeping it simple with a single disk.
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 encryption=aes-256-gcm \
-O keyformat=passphrase \
-O keylocation=prompt \
zroot /dev/disk/by-id/id-to-disk
Create ZFS Datasets
Root datasets:
zfs create -o mountpoint=none zroot/data
zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/default
zfs create -o mountpoint=/home zroot/data/home
System datasets. I’d recommend these:
zfs create -o mountpoint=/var -o canmount=off zroot/var
zfs create zroot/var/log
zfs create -o mountpoint=/var/lib -o canmount=off zroot/var/lib
Optional datasets for libvirt and Docker:
zfs create zroot/var/lib/libvirt
zfs create zroot/var/lib/docker
Export and Import Your Pool
Not strictly required, but it’s a good sanity check. Export and re-import to make sure everything is configured right:
zpool export <Pool Name> # e.g. zpool export zroot
zpool import <Pool Name> -R /mnt # e.g. zpool import zroot -R /mnt
Mount ZFS Datasets
Mount the root dataset first:
zfs mount <Pool Name>/ROOT/<ROOT Dataset> # e.g. zfs mount zroot/ROOT/default
Then everything else:
zfs mount -a
Mount Boot and EFI
mount <Path to Boot partition> /mnt/boot
mount <Path to EFI Partition> /mnt/boot/efi
Pacstrap base
Bootstrap the base system:
pacstrap /mnt base base-devel
Generate fstab
genfstab -f /boot -U /mnt > /mnt/etc/fstab
No need to include ZFS datasets here. GRUB and the ZFS manager handle mounting those automatically.
Now chroot in:
arch-chroot /mnt
Install The Kernel
You’ve got three options:
- linux — vanilla kernel
- linux-zen — tuned for desktop/laptop use
- linux-lts — long term support
Install whichever you prefer:
pacman -Syy <Kernel> <Kernel>-headers
# e.g. pacman -Syy linux-zen linux-zen-headers
You can install multiple kernels side by side if you want.
Install CPU Microcode
- AMD:
pacman -S amd-ucode - Intel:
pacman -S intel-ucode
Install ZFS
Add the archzfs repo
Append this to /etc/pacman.conf:
[archzfs]
Server = https://archzfs.com/$repo/$arch
Add their signing keys:
pacman-key -r DDF7DB817396A49B2A2723F7403BD972F75D9D76
pacman-key --lsign-key DDF7DB817396A49B2A2723F7403BD972F75D9D76
Refresh:
pacman -Syy
Install the ZFS kernel module
pacman -S zfs-dkms
This compiles ZFS from source for all installed kernels, so it might take a few minutes.
Configure initramfs
Edit /etc/mkinitcpio.conf. Add ZFS to the HOOKS line. It should look like:
HOOKS=(base udev autodetect modconf block keyboard zfs filesystems)
The keyboard hook goes before zfs so you can actually type your pool password at boot. We skip fsck since ZFS doesn’t need it.
Regenerate initramfs:
mkinitcpio -P
Configure systemd
Set a cache file for your pool:
zpool set cachefile=/etc/zfs/<Pool Name>.cache <Pool Name>
Enable the ZFS systemd services:
systemctl enable zfs-mount zfs-import-scan zfs-import-cache
Install the Bootloader
We’re using GRUB with UEFI:
pacman -S grub efibootmgr os-prober
Install GRUB to disk
ZPOOL_VDEV_NAME_PATH=1 grub-install --efi-directory=<EFI Mountpoint> \
--bootloader-id=<Desired Name> --target=x86_64-efi
# e.g. ZPOOL_VDEV_NAME_PATH=1 grub-install --efi-directory=/boot/efi \
# --bootloader-id="ArchZFS" --target=x86_64-efi
Generate GRUB config
ZPOOL_VDEV_NAME_PATH=1 grub-mkconfig -o /boot/grub/grub.cfg
GRUB assumes the kernel will be booted from the pool as root, but the path needs a small fix. Replace /ROOT with <Pool Name>/ROOT:
sed -i "s@/ROOT@<Pool Name>/ROOT@" /boot/grub/grub.cfg
# e.g. sed -i "s@/ROOT@zroot/ROOT@" /boot/grub/grub.cfg
You only need to do this once, or when you add a new kernel.
Set Timezone and Locale
Timezone
ln -s /usr/share/zoneinfo/<Your Timezone> /etc/localtime
hwclock --systohc
# e.g. ln -s /usr/share/zoneinfo/Asia/Kolkata /etc/localtime
Locale
Uncomment your locale in /etc/locale.gen (usually en_US.UTF-8), then:
locale-gen
echo "LANG=en_US.UTF-8" >> /etc/locale.conf
Install Recommended Packages
NTP
pacman -S ntp
systemctl enable ntpd
Text Editor
pacman -S nano
Networking
pacman -S networkmanager dhcpcd iwd
systemctl enable dhcpcd NetworkManager
Configure Users
Set root password:
passwd
Create your user:
useradd -m <user>
passwd <user>
If you skip the -m flag, fix the permissions manually:
chown <user>:<user> /home/<user>
Install a Desktop Environment (Optional)
The Arch wiki has a full guide. For a basic KDE setup:
pacman -S plasma pipewire pipewire-pulse sddm pipewire-media-session konsole
For Wayland:
pacman -S plasma-wayland-session
Unmount and Reboot
exit
umount /mnt/boot/efi
umount /mnt/boot
zpool export <Pool Name> # e.g. zpool export zroot
reboot
You’ll be asked for your pool password on every boot.
You can also use shavee to encrypt home directories with a separate key.
Let me know if I missed anything.