Skip to content

Instantly share code, notes, and snippets.

@apsun
Last active August 13, 2024 04:37
Show Gist options
  • Save apsun/1f7b1da40b028a9ed1e0409ca8c3b3cc to your computer and use it in GitHub Desktop.
Save apsun/1f7b1da40b028a9ed1e0409ca8c3b3cc to your computer and use it in GitHub Desktop.

Encrypted Arch Linux on UEFI

This documents how to install Arch Linux with full disk encryption under UEFI (not using secure boot, although it will be easy to enable later on if you want it). It assumes you're familiar with installing Arch Linux, but new to encryption/UEFI.

Partition the disk

Boot into the Arch Linux live USB and enter the installation environment.

Hereafter, /dev/nvme0n1 refers to the disk you are installing Arch on. /dev/nvme0n1p1 refers to the EFI system partition, and /dev/nvme0n1p2 refers to the encrypted Linux partition.

  1. Run gdisk /dev/nvme0n1. Create the GPT (o), then create two partitions (n):
    • EFI system partition (hex code EF00, size 550MiB)
    • Linux LUKS partition (hex code 8309, fill remainder of disk)
    • Commit the changes with w when you're done
  2. Create a FAT32 filesystem on the EFI system partition (mkfs.fat -F32 /dev/nvme0n1p1)
  3. Create a LUKS container on the Linux partition:
    • Encrypt the partition (cryptsetup -y -v luksFormat /dev/nvme0n1p2)
    • Open the partition as "cryptroot" (cryptsetup open /dev/nvme0n1p2 cryptroot)
    • Create your ext4 filesystem on top (mkfs.ext4 /dev/mapper/cryptroot)
  4. Mount the partitions
    • Linux (mount /dev/mapper/cryptroot /mnt)
    • ESP (mount --mkdir -o umask=077 /dev/nvme0n1p1 /mnt/efi)

Steps 2-4 are taken from the LUKS on a partition section on the wiki.

Install the system

Follow the installation guide from the wiki. Stop after configuring the hostname. You'll likely also want to install the following packages:

  • sudo
  • vim (or the editor of your choice)
  • bash-completion
  • amd-ucode/intel-ucode
  • wpa_supplicant (if using WiFi)

Create a user account

This will create a new account, set its password, and enable sudo:

useradd -m -G wheel ${YOUR_UNIXNAME}
passwd ${YOUR_UNIXNAME}
visudo  # uncomment the relevant line

Configure the network

For an Ethernet connection, put this in /etc/systemd/network/20-wired.network (note the .network extension, not .conf):

[Match]
Name=en*

[Network]
DHCP=yes

If you are using WiFi, replace en* with wl*, and also edit /etc/wpa_supplicant/wpa_supplicant-${INTERFACE}.conf:

ctrl_interface=/run/wpa_supplicant
update_config=1

network={
	ssid="<SSID>"
	psk="<PSK>"
}

If you configured both WiFi and Ethernet, configure systemd-networkd-wait-online.service to wait for any instead of all interfaces to be up:

[Service]
ExecStart=
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --any

Next, enable the systemd units:

systemctl enable systemd-networkd
systemctl enable systemd-resolved
systemctl enable wpa_supplicant@${INTERFACE}  # if using WiFi

You may need to set the regulatory domain for your WiFi card too.

Also remember to fix up /etc/resolv.conf after installation is complete by following the instructions on the systemd-resolved wiki.

Configure the initramfs

Edit /etc/mkinitcpio.conf and change the HOOKS=(...) line to:

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

This makes the partition decryption password prompt work. Note that we put keyboard before autodetect to ensure that all drivers are loaded. This is especially important if you have a laptop with an external keyboard.

Note that this configures your initramfs to use systemd (sd-encrypt supports echoing * when entering the password, unlike busybox). If you want the busybox-based initramfs, use this instead:

HOOKS=(base udev keyboard autodetect microcode modconf kms block encrypt filesystems fsck)

You may also want to add your video driver to /etc/mkinitcpio.conf too, to enable modesetting early in boot. This prevents Xorg "no screens found" race condition errors at startup. See the early KMS start section in the wiki. tl;dr, change the MODULES=() line to:

MODULES=(amdgpu)

(replace amdgpu with the driver for your GPU).

Generate a unified kernel image

For a systemd-based initramfs, run (replace /dev/nvme0n1p2 with the encrypted partition from earlier):

echo "luks.name=$(blkid -s UUID -o value /dev/nvme0n1p2)=cryptroot root=/dev/mapper/cryptroot rw quiet" > /etc/kernel/cmdline

If you choose to use a busybox-based initramfs, instead run:

echo "cryptdevice=UUID=$(blkid -s UUID -o value /dev/nvme0n1p2):cryptroot root=/dev/mapper/cryptroot rw quiet" > /etc/kernel/cmdline

Next, edit /etc/mkinitcpio.d/linux.preset and:

  1. comment out the default_image= line
  2. uncomment the default_uki= line
#default_image="/boot/initramfs-linux.img"
default_uki="/efi/EFI/Linux/arch-linux.efi"

For faster mkinitcpio runs, also remove the fallback preset by changing the PRESETS= line to just PRESETS=('default'). Note that this means a botched system upgrade has a higher chance of requiring you to boot into the installer to recover the system.

Finally, run mkdir -p /efi/EFI/Linux; mkinitcpio -P to generate the unified kernel image, then bootctl install to install systemd-boot. It will automatically detect the unified kernel image, so no configuration is required.

Success!

Exit the chroot, unmount everything, and reboot. You should be presented with a decryption prompt. Your system is now ready to use!

Shrinking the partition

Suppose that at a later time, you wish to shrink the encrypted partition.

Boot into the Arch Linux live USB again, and open the encrypted partition (but don't mount the filesystem):

cryptsetup open /dev/nvme0n1p2 cryptroot

Determine how large you want your filesystem to be, then figure out how many sectors (512B blocks) that is. For example, a 500GiB filesystem is 500 * 1024^3 / 512 = 1048576000 sectors. Note that LUKS adds about 16MiB of overhead on top of this, so the partition will be slightly larger than the filesystem.

Next, shrink the filesystem:

e2fsck -f /dev/mapper/cryptroot
resize2fs /dev/mapper/cryptroot ${FILESYSTEM_SIZE_IN_SECTORS}s

Note the s at the end, indicating that the unit is in sectors. Once the filesystem is resized (it may take a few minutes), shrink the LUKS volume:

cryptsetup -b ${FILESYSTEM_SIZE_IN_SECTORS} resize cryptroot

Finally, follow the steps on the Arch Wiki to resize the partition. Note that the partition size is larger than the filesystem size by however much the LUKS header is (in my case, 16MiB).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment