Installing Arch Linux with Btrfs, systemd-boot and LUKS
My preferred Arch Linux setup is with Btrfs, systemd-boot (which requires UEFI) and - at least when installing a laptop - LUKS. Not least to make the next installation easier for myself, I thought it would be a good idea to document the steps.
Note
This post describes the creation and usage of a swap file, but that's optional.
Using SSH
If you have another PC, it's convenient to do the installation from this PC via SSH because then you can have browser windows with installation guides open in parallel and easily copy and paste commands. To do so, boot the PC that you want to install from the Arch Linux ISO. The SSH daemon is already running on the ISO.
Set a password for root:
passwd
Look up the IP address of the PC:
ip addr
Now, on the second PC, connect to the first PC via SSH:
ssh root@<IP-OF-THE-FIRST-PC>
and continue with the installation.
Partitioning
Note
For the rest of this post, we assume that we install Arch Linux on an SSD with the device path /dev/nvme0n1.
Adjust the steps for your setup if necessary.
gdisk /dev/nvme0n1
Create a new partition table:
Command (? for help): o
Create an EFI partition (choose size 1G and hex code EF00):
Command (? for help): n
Create a root partition (accept the default values):
Command (? for help): n
Write the new partitions to disk:
Command (? for help): w
Encryption
Create an encrypted container for the root file system (you need to define a passphrase):
cryptsetup luksFormat /dev/nvme0n1p2
Open the container ("root" is just a placeholder; you can use a name of your choice, but remember to adapt the subsequent steps of the guide accordingly):
cryptsetup open /dev/nvme0n1p2 root
Create file systems
Format the EFI partition with FAT32 and give it the label EFI - you can choose any other label name:
mkfs.vfat -F32 -n EFI /dev/nvme0n1p1
Format the root partition with Btrfs and give it the label SYSTEM - you can choose any other label name. If you didn't open the LUKS container under the name "root", you must adjust the command accordingly:
mkfs.btrfs -L SYSTEM /dev/mapper/root
Create and mount subvolumes
Note
If you don't want to use a swap file, it is not required to create and mount the subvolume @swap.
Create subvolumes for root, home, cache, log, tmp, and snapshots (cache, log and tmp get separate subvolumes since I want to be able to create snapshots of root without all the temporary and cached data of /var/cache, /var/log and /var/tmp):
mount /dev/mapper/root /mnt
btrfs sub create /mnt/@
btrfs sub create /mnt/@home
btrfs sub create /mnt/@cache
btrfs sub create /mnt/@log
btrfs sub create /mnt/@tmp
btrfs sub create /mnt/@snapshots
btrfs sub create /mnt/@swap
umount /mnt
Mount the subvolumes:
mount --mkdir -o noatime,compress=zstd,subvol=@ /dev/mapper/root /mnt
mount --mkdir -o noatime,compress=zstd,subvol=@home /dev/mapper/root /mnt/home
mount --mkdir -o noatime,compress=zstd,subvol=@cache /dev/mapper/root /mnt/var/cache
mount --mkdir -o noatime,compress=zstd,subvol=@log /dev/mapper/root /mnt/var/log
mount --mkdir -o noatime,compress=zstd,subvol=@tmp /dev/mapper/root /mnt/var/tmp
mount --mkdir -o noatime,compress=zstd,subvol=@snapshots /dev/mapper/root /mnt/.snapshots
mount --mkdir -o noatime,compress=zstd,subvol=@swap /dev/mapper/root /mnt/swap
Note
- Most Btrfs mount options apply to the whole file system, not to individual subvolumes. That's why all subvolumes are mounted with the same options.
- Other options that used to be set explicitly are default nowadays:
space_cache=v2(since btrfs-progs 5.15),ssd(detected automatically) anddiscard=async(since Linux 6.2, for devices that support it).
Mount the EFI partition:
mount --mkdir /dev/nvme0n1p1 /mnt/boot
Create a swap file (see Btrfs - Swap file). btrfs filesystem mkswapfile takes care of the Btrfs specifics, such as disabling copy-on-write and compression for the file:
btrfs filesystem mkswapfile --size <FILE-SIZE-IN-GiB>g --uuid clear /mnt/swap/swapfile
swapon /mnt/swap/swapfile
Base system and /etc/fstab
Install Arch Linux (adjust this list to your needs):
pacstrap -K /mnt linux linux-firmware base intel-ucode btrfs-progs efibootmgr gptfdisk dosfstools nano
Note
- On a system with an AMD CPU, install
amd-ucodeinstead ofintel-ucode. - Don't forget to install network management software (e.g.,
networkmanager) and to enable its systemd unit. Otherwise, the new system has no network connection after the reboot.
Generate /etc/fstab:
genfstab -U /mnt >> /mnt/etc/fstab
Enable periodic trim
To enable periodic trim, execute
systemctl --root=/mnt enable fstrim.timer
Note
If your disk is not an SSD, you do not need this.
System configuration
Since I want a German system, the following steps are set up accordingly. Adjust them to your needs.
chroot into the new system:
arch-chroot /mnt/
Set host name:
echo <YOUR-HOSTNAME> > /etc/hostname
Set locale:
echo LANG=de_DE.UTF-8 > /etc/locale.conf
Uncomment the following lines of /etc/locale.gen:
#de_DE.UTF-8 UTF-8
#de_DE ISO-8859-1
#de_DE@euro ISO-8859-15
Generate locale:
locale-gen
Set keyboard layout and font:
echo KEYMAP=de-latin1 > /etc/vconsole.conf
echo FONT=lat9w-16 >> /etc/vconsole.conf
Set time zone:
ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime
Set the hardware clock and generate /etc/adjtime:
hwclock --systohc
Define hosts in /etc/hosts:
127.0.0.1 localhost
::1 localhost
127.0.1.1 <YOUR-HOSTNAME>.localdomain <YOUR-HOSTNAME>
Set root password:
passwd
Initramfs
Configure the creation of initramfs by editing /etc/mkinitcpio.conf. Change the line HOOKS=... to:
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)
Note
- Here, we are using a systemd-based RAM disk. It already contains everything required to resume from hibernation, so no
resumehook is needed. - The
btrfshook is only required for Btrfs file systems that span multiple devices.
Recreate initramfs:
mkinitcpio -P
Boot manager
Install systemd-boot:
bootctl install
Since the ESP is mounted at /boot, bootctl finds it automatically. systemd-boot is updated automatically whenever the systemd package is upgraded.
Create the file /boot/loader/entries/archlinux.conf and fill it with:
title Arch Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options rd.luks.name=<UUID-OF-SYSTEM-PARTITION>=root root=/dev/mapper/root rootflags=subvol=@ rd.luks.options=discard rw resume=/dev/mapper/root resume_offset=<SWAPFILE-OFFSET>
The offset of the swap file can be determined with this command:
btrfs inspect-internal map-swapfile -r /swap/swapfile
Note
- Do not use
filefragto determine the offset (as recommended for other file systems). On Btrfs, it does not return the real physical offset on the disk. - If you don't use a swap file, leave out the options
resumeandresume_offset. - On UEFI systems, systemd stores the location of the hibernation image in an EFI variable when hibernating. Thus,
resumeandresume_offsetare not strictly necessary. Specifying them explicitly is a fallback in case that mechanism does not work.
The UUID of the system partition (i.e., the LUKS container) can be determined via:
blkid -s UUID -o value /dev/nvme0n1p2
Edit the file /boot/loader/loader.conf and fill it with:
default archlinux.conf
timeout 4
console-mode max
editor no
Final steps
Exit chroot, unmount partitions and reboot:
exit
umount -R /mnt
reboot
Have fun with your system!
References
- Arch My Way 1 | Grundsystem installieren (German) is a nice guide to an Arch Linux installation with Btrfs
- Arch Linux - UEFI, systemd-boot, LUKS, and btrfs is a helpful blog post about an Arch Linux installation with systemd-boot, LUKS and Btrfs