2024-12-24


Arch Linux for Fun and Profit in 2025 — Installing Arch with Full Disk Encryption

Motivation

My computing setup has expanded since I shared my first public note earlier this year. In addition to my reliable Lenovo Thinkpad T480, I have since built an x86-64 based small form factor (SSF) PC. My plans for this new machine include productivity and programming use — and perhaps the occasional match of CS2. Naturally, I have installed my preferred Linux distro (Arch, btw).

This note includes the full installation sequence and some of my learnings.

Contents:

Philosophy

My philosophy is to keep my install light-weight and as stable as possible, despite the rolling release distribution model employed by Arch. The minimal base package, extensive documentation, pacman, and the combination of yay and the AUR, I think, has cemented Arch as my preferred distro for personal or professional use (Xubuntu for enterprise work). I am willing to accept that things may break sometimes and see it as a learning opportunity. I've opted to follow a minimal and proven set-up paradigm as you will find below — it follows that I've chosen to keep using X in lieu of Wayland for the forseeable future.

My Setup

arch release: 2024.12.01
arch version: x86_64
init system: systemd
boot mode: UEFI 
bootloader: GRUB
display server: X
desktop environment: xfce4
window manager: xwfm4
network manager: iwd w/ built in DHCP

Partitioning Scheme

Before beginning the install, it is important to think about the partioning scheme. The below assumes the use of a GUID Partition Table (GPT).

Option #1: Full Disk Encryption (encrypted /boot)

NAME          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINTS
nvme0n1       259:0    0  1.8T  0 disk  
├─nvme0n1p1   259:1    0  500M  0 part  /efi
├─nvme0n1p2   259:2    0    1G  0 part  
│ └─cryptboot 254:0    0    1G  0 crypt /boot
├─nvme0n1p3   259:3    0  100G  0 part  
│ └─cryptroot 254:1    0  100G  0 crypt /
└─nvme0n1p4   259:4    0  1.6T  0 part  
  └─crypthome 254:2    0  1.6T  0 crypt /home

This scheme provides the greatest level of security by decreasing the attack surface of the system. An encrypted boot partition protects against the Evil Maid attack where a nefarious actor with physical access to the system compromises the kernel and initramfs image when the user is logged on and the computer is left unnattended. The EFI System Partition (ESP) containing the bootloader is mounted to /efi and is the only unencrypted block. No secrets are stored on the unencrypted ESP.

A major draw-back of this scheme is the added complexity and the longer boot time. When the system boots, the bootloader must access the kernel and the initramfs image. With an encrypted /boot, the bootloader must first decrypt the partition to gain access to its content. Luckily, GRUB provides the ability to unlock encrypted LUKs devices. However, as I found out first-hand, GRUB is excrutiatingly slow at performing this function. In my testing, it took GRUB almost (20) seconds to unlock /boot, which is simply not acceptable for many who daily drive their machine or use it for productivity.

Though I initially went with Option #1 and an encrypted /boot for the added security, I quickly grew tired of the increased boot times, so I wiped my system and started from scratch using Option #2 with non-encrypted /boot partition. Instructions for Option #1 (full disk encryption) are included in these notes, for posterity and to allow others to try it out for themselves. In my case, it was not worth it.

Option #2: Block Device Encryption (non-encrypted /boot)

NAME          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINTS
nvme0n1       259:0    0  1.8T  0 disk  
├─nvme0n1p1   259:1    0    1G  0 part  /boot
├─nvme0n1p2   259:2    0  100G  0 part  
│ └─cryptroot 254:0    0  100G  0 crypt /
└─nvme0n1p3   259:3    0  1.7T  0 part  
  └─crypthome 254:1    0  1.7T  0 crypt /home

This scheme encrypts everything but /boot. Consequently, the system remains vulnerable to Evil Maid attacks, at least in theory. This seems to be the most common setup for its lesser complexity and shorter boot times when compared to the alternative. All secrets are kept in the encrypted partitions, and unless you make a habit of leaving your system logged in and physically unnattended around unknown individuals, your kernel and initramfs will most likely not be tampered with. I highly encourage others to try both schemes for themselves; it is satisfying to confirm your preference first-hand.

Enough background, below is the installation sequence:

Installation Sequence

Reference Arch Linux Installation Guide

  1. Create desired partitioning scheme using fdisk
    • See Option #1 or Option #2 above.
  2. Prepare and mount the non-boot partitions
    • Create and unlock LUKS root device
      • cryptsetup -v luksFormat /dev/<root_partition>
      • cryptsetup open /dev/<root_partition> <cryptroot>
    • Create file system and mount the encrypted root partitiion
      • mkfs.ext4 /dev/mapper/<cryptroot>
      • mount /dev/mapper/<cryptroot> /mnt
    • Repeat the same steps for /home
      • cryptsetup -v luksFormat /dev/<home_partition>
      • cryptsetup open /dev/<home_partition> <crypthome>
      • mkfs.ext4 /dev/mapper/<crypthome>
      • mount --mkdir /dev/mapper/<crypthome> /mnt/home
      • Note: cryptroot and crypthome can be any name you choose but must remain subsequently consistent
  3. Prepare and mount the boot partition
    • For Option #1: Encrypted /boot
      • Must use LUKS2 with PBKDF2 for partitions that GRUB will need to unlock
        • cryptsetup luksFormat --pbkdf pbkdf2 <boot_partition>
      • cryptsetup open /dev/<boot_partition> <cryptboot>
      • mount /dev/mapper/<cryptboot> /mnt/boot
    • For Option #2: Unencrypted /boot
      • mkfs.fat -F32 <boot_partition>
      • mount --mkdir <boot_partition> /mnt/boot
  4. Install essential packages with pacstrap
    • pacstrap -K /mnt base linux linux-firmware
    • Recommended:
      • text editor
        • vi, vim, nvim
      • manual pages
        • man-db, man-pages
      • utilities
        • unzip, sudo, openssh
      • networking
        • iwd
      • console fonts
        • terminus-font
      • bootloader
        • grub
        • efibootmgr
  5. Generate fstab
    • genfstab -U /mnt >> /mnt/etc/fstab
  6. Change the apparent root directory
    • arch-chroot /mnt
  7. Set timezone
    • ln -sf /usr/share/zoneinfo/Region/City /etc/localtime
  8. Generate /etc/adjtime
    • hwclock --systohc
  9. Revise /etc/locale.gen to uncomment en_US.UTF-8
  10. Create the hostname file
    • echo "myhostname" > /etc/hostname
  11. Configure /etc/mkinitcpio.conf
    • Note: my set up uses a busybox-based initramfs; the hooks are different for systemd-based initramfs
    • Add 'encrypt' option to HOOKS
      • HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt filesystems fsck)
    • Add keyfile for root paretition to FILES
      • FILES=(/etc/cryptsetup-keys.d/cryptroot.key)
  12. Regenerate initramfs
    • mkinitcpio -P
  13. Create keyfile and add as LUKS key for root and home partitions
    • dd bs=512 count=4 if=/dev/random iflag=fullblock | install -m 0600 /dev/stdin /etc/cryptsetup-keys.d/cryptroot.key
    • cryptsetup -v luksAddKey /dev/nvme0n1p2 /etc/cryptsetup-keys.d/cryptroot.key
    • dd bs=512 count=4 if=/dev/random iflag=fullblock | install -m 0600 /dev/stdin /etc/cryptsetup-keys.d/crypthome.key
    • cryptsetup -v luksAddKey /dev/nvme0n1p3 /etc/cryptsetup-keys.d/crypthome.key
  14. Set root password
    • passwd
  15. Install grub and efibootmgr (if not installed with pacstrap)
    • pacman -S grub efibootmgr
  16. Install bootloader
    • grub-install --target=x86_64_efi --efi-directory=/boot --bootloader-id=GRUB
  17. Configure GRUB
    • Determine UUID of LUKS device (FSTYPE: crypto_LUKS) containing the encrypted root partition
      • lsblk -f
    • Edit /etc/default/grub with the following:
      • GRUB_ENABLE_CRYPTODISK=y
      • GRUB_CMDLINE_LINUX="cryptdevice=UUID=UUID_of_LUKS_device root=dev/mapper/<cryptroot>"
  18. Edit /etc/crypttab to append:
    • For Option #1: Encrypted /boot
      • crypthome UUID=UUID_of_LUKS_DEVICE /etc/cryptsetup-keys.d/crypthome.key
    • For Option #2: Non-Encrypted /boot
      • cryptboot UUID=UUID_of_LUKS_DEVICE /etc/cryptsetup-keys.d/cryptboot.key
      • crypthome UUID=UUID_of_LUKS_DEVICE /etc/cryptsetup-keys.d/crypthome.key
  19. Generate /boot/grub/grub.cfg
    • grub-mkconfig -o /boot/grub/grub.cfg
  20. Add user and password
    • useradd -m user
      • Using the -m option creates the home directory and sets the proper permissions
    • passwd user
  21. Configure network tools
    • Create /etc/iwd/main.conf
      • Append the following to enable built-in DHCP functionality via sysetmd-resolved:
        [General]
        EnableNetworkConfiguration=true
        
    • Start and enable network services: systemctl enable --now iwd.service systemctl enable --now systemd-resolved.service
  22. (Optional) Edit /etc/vconsole.conf to add larger font
    • Regenerate initramfs with mkinitcpio -P to ensure console font is loaded early in boot sequence
  23. (Optional) For Nvidia GPU (RTX family)
    • Install linux-headers if using nvidia DKMS drivers
  24. (Optional) Enable vi mode in the terminal
    • For interactive shell (bash)
      • Append set -o vi to .bashrc
  25. (Optional) Enable insults for sudo
  26. Reboot and enjoy!!