How to Install Arch Linux with LUKS

In this guide we will see how to install a minimal Arch Linux system on a UEFI x86_64 machine with LUKS encryption. The setup uses an “almost full” disk layout, meaning that the root partition will be encrypted while the boot partition will remain unencrypted. We will also configure the bootloader using systemd-boot.

Before proceeding, download the relevant ISO files from the Arch website and flash it on a spare USB drive.

Networking

I will assume that you already have an established Internet connection. To check whether everything is working, try to send some ICMP packets:

# ping google.com -c 4
PING google.com (142.251.110.102) 56(84) bytes of data.
64 bytes from bz-in-f102.1e100.net (142.251.110.102): icmp_seq=1 ttl=111 time=45.9 ms
64 bytes from bz-in-f102.1e100.net (142.251.110.102): icmp_seq=2 ttl=111 time=46.0 ms
64 bytes from bz-in-f102.1e100.net (142.251.110.102): icmp_seq=3 ttl=111 time=44.7 ms
64 bytes from bz-in-f102.1e100.net (142.251.110.102): icmp_seq=4 ttl=111 time=45.6 ms

--- google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 44.670/45.544/45.992/0.521 ms

Also, before proceeding, synchronize your system clock using NTP.

# timedatectl set-ntp true

Disk Partition

As mentioned earlier, we will encrypt the root partition while leaving the boot one (which will also include the bootloader) unencrypted. In other words, we want to create the following partitions:

Name Type Mount Point Size
/dev/nvme0n1p1 EFI /boot 1 GiB
/dev/nvme0n1p2 LUKS n/a 100 %

You can create them using fdisk(8). Once created, format them with the following commands:

# mkfs.vfat -F32 /dev/nvme0n1p1
# cryptsetup luksFormat /dev/nvme0n1p2 # Create
# cryptsetup luksOpen /dev/nvme0n1p2 root # Open
# mkfs.ext4 /dev/mapper/root # Format

After that we can mount these partitions on /mnt:

# mount /dev/mapper/root /mnt
# mkdir -p /mnt/boot
# mount /dev/nvme0n1p1 /mnt/boot

Repository settings

Before bootstrapping the system, it’s advisable to update the /etc/pacman.d/mirrorlist file using a tool such as rankmirror(8). To do that, first install the pacman-contrib package on the live system and then retrieve the fastest mirrors for your location:

# pacman -Sy pacman-contrib
# rankmirrors -v -n 5 /etc/pacman.d/mirrorlist > /tmp/mirrors

Finally, use the /tmp/mirrors file as the mirror list:

# mv /tmp/mirrors /etc/pacman.d/mirrorlist
# pacman -Sy

Bootstrapping

We are now ready to install the base system. To do that, issue the following command:

# pacstrap -i -K /mnt base linux-lts linux-firmware vim dhcpcd sudo

Once done, we need to generate an fstab file. Instead of doing it manually, we can use the following neat utility.

# genfstab -U /mnt >> /mnt/etc/fstab

Then let’s change the root directory to /mnt:

# arch-chroot /mnt

Configure the system

Let’s start by configuring the timezone:

(chroot)# ln -sf /usr/share/zoneinfo/<AREA>/<LOCATION> /etc/localtime
(chroot)# hwclock --systohc
(chroot)# timedatectl set-ntp true

Then, let’s configure localization:

(chroot)# vim /etc/locale.gen # Edit accordingly
(chroot)# locale-gen
(chroot)# echo "LANG=en_US.UTF-8" > /etc/locale.conf

Now the hostname:

(chroot)# echo "<HOSTNAME>" > /etc/hostname
(chroot)# vim /etc/hosts # Add <HOSTNAME> to 127.0.0.1

And finally the users:

(chroot)# passwd
(chroot)# useradd -m -G wheel,video,audio -s /bin/bash <USER_NAME>
(chroot)# passwd <USER_NAME>
(chroot)# EDITOR=vim visudo # Uncomment '%wheel...' part

Do not forget to enable the DHCP daemon (dhcpcd(8)) using systemctl enable dhcpcd.

Bootloader and initramfs

Let’s now move on the most delicate part of the whole guide. The outcome of this section will determine whether the system will be able to boot or not. As stated at the begin of the post, we will use systemd-boot(7).

Let’s start by configuring the initial ram disk. This small file system includes the components needed by the kernel to unlock and mount the root partition. In our case, we will need to instruct the system to include the “encrypt” module every time this file systems gets rebuilt.

To do that, we can edit the /etc/mkinitcpio.conf file by adding the following values.

HOOKS=(base systemd autodetect microcode modconf kms keyboard keymap consolefont block sd-encrypt filesystems fsck)

That is, we need to add the systemd and the sd-encrypt (systemd-encrypt) hooks in the HOOKS array.

Arch Linux also requires you to specify the keymap in use by editing the /etc/vconsole.conf file:

KEYMAP=us

After that, generate a new initramfs file with the following command:

(chroot)# mkinitcpio -P

Then, we can procceed by configuring the bootloader. First of all, we need to install it on the /boot directory:

(chroot)# bootctl --path=/boot install

Then, let’s edit the /boot/loader/loader.conf file by adding the following content:

default arch-lts
timeout 3
editor 0

With the previous settings, the bootloader will look for a loader called arch-lts.conf, let’s create it:

(chroot)# cat /boot/loader/entries/arch-lts.conf
title Arch Linux (LTS)
linux /vmlinuz-linux-lts
initrd /initramfs-linux-lts.img
options rd.luks.name=<ROOT_UUID>=root rd.luks.options=discard root=/dev/mapper/root rw

Where the <ROOT_UUID> placeholder must be replaced with the UUID of the root partition. This value can be retrieved with:

(chroot)# lsblk -o name,fstype,uuid,mountpoints
NAME        FSTYPE      UUID                                 MOUNTPOINTS
nvme0n1
├─nvme0n1p1 vfat        25TF-ARZ9                            /boot
└─nvme0n1p2 crypto_LUKS f1911b3b-88b7-4470-a067-40ab9f995b8b
  └─root    ext4        ca985a40-96ac-43b8-8d31-3515d072596a /

In the previous example, the relevant UUID is f1911b3b-88b7-4470-a067-40ab9f995b8b (the second-to-last).

Finally, run the following command to validate the loaders:

(chroot)# bootctl status
Available Boot Loaders on ESP:
          ESP: /boot
         File: ├─/boot//EFI/systemd/systemd-bootx64.efi (systemd-boot 260.1-1-arch)
               └─/boot//EFI/BOOT/BOOTX64.EFI (systemd-boot 260.1-1-arch)

Boot Loader Entry Locations:
          ESP: /boot ($BOOT)
       config: /boot//loader/loader.conf
        token: arch

Default Boot Loader Entry:
         type: Boot Loader Specification Type #1 (.conf)
        title: Arch Linux (LTS)
           id: arch-lts.conf
       source: /boot//loader/entries/arch-lts.conf (on the EFI System Partition)
        linux: /boot//vmlinuz-linux-lts
       initrd: /boot//initramfs-linux-lts.img
      options: rd.luks.name=f1911b3b-88b7-4470-a067-40ab9f995b8b=root rd.luks.options=discard root=/dev/mapper/root rw

TRIM support

The rd.luks.options=discard option of the previous section will enable TRIM support. These flags allow the kernel to pass TRIM commands to the drive’s firmware, which are used to perform essential maintenance operations such as garbage collection and cell wear optimization. While this feature is important for maintaining optimal performance over time, it can potentially leak metadata, revealing unused block information that may be used to identify the filesystem in use.

For this reason, cryptsetup developers advise against enabling such feature in all those scenarios where maximum privacy is required. In any other cases, leaving this option enabled will ensure long-term SSD health. More information about this topic can be found on the Arch wiki.

Reboot

After that we can exit from the chroot environment, umount the partitions using:

# umount -R /mnt

And then reboot the system.

That’s it. Enjoy your encrypted Arch Linux installation! 😉