Install Arch Linux on Encrypted Disk

23 July 2023

I installed Arch Linux before but using archinstall script. archinstall is a helper library which automates the installation. It is packaged with different pre-configured installers that work like a "guided" installer. Linux enthusiasts will oppose to this way of installing since Arch Linux is meant to be DIY.

Then I attempted to do the encrypted version using the same archinstall. I am not happy with the result due to the following reasons.

On this post, I will put the step by step guide I followed for an encrypted Arch Linux setup. I had three attempts before I get a working one. Common issue I have is along bootloader and missing resume hook to wake up from deep sleep. I learned my lessons the hard way!

This setup will create an LVM on LUKS with GRUB boot loader.

Preparing the USB boot disk

The steps here are for Linux users. If you're a Windows user, please look for alternative way from Arch Linux Wiki. rufus or Balena etcher will do the job for you.

  1. Download the .iso image from Arch Linux website. I downloaded mine using qBittorrent.

  2. Plug your USB drive stick and check it's location usng lsblk.

    $ lsblk
    NAME          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINTS
    sda             8:0    1  7.5G  0 disk  
    ├─sda1          8:1    1  798M  0 part  /run/media/drmanalo/ARCH_202307
    └─sda2          8:2    1   15M  0 part
    
  3. Verify the file integrity using its checksum from the Arch Linux Download Page.

    $ sha256sum archlinux-2023.07.01-x86_64.iso
    1a2c1cdea0118b60525f55ee616e9cd4cf68fe17db906ce3d8e46fd06f9907eb  archlinux-2023.07.01-x86_64.iso
    
  4. Burn the .iso image with the dd tool.

    $ sudo dd bs=4M if=/path/to/archlinux-2023.07.01-x86_64.iso of=/dev/sda oflag=sync status=progress
    852832256 bytes (853 MB, 813 MiB) copied, 210 s, 4.1 MB/s
    203+1 records in
    203+1 records out
    852832256 bytes (853 MB, 813 MiB) copied, 209.578 s, 4.1 MB/s
    
  5. Let your machine reboot from the live USB. The prompt should say root@archiso. Below is optional should the default font be small for your eyes.

    root@archiso ~ # setfont latarcyrheb-sun32
    

Pre-installation

  1. Plug in your Ethernet cable or connect to your WiFi network using iwctl.

  2. Update the system clock.

    # timedatectl set-ntp true
    
  3. Partition your disk. nvme0n1 is my block device name. Use lsblk to find yours. Once on gdisk, delete existing partitions using d.

    # gdisk /dev/nvme0n1
    o
    n
    [Enter]
    0
    +1M
    ef02
    n
    [Enter]
    [Enter]
    +550M
    ef00
    n
    [Enter]
    [Enter]
    [Enter]
    8309
    w
    

Installation

  1. Create the Linux Unified Key Setup (LUKS) encrypted container on your ext4 partition.

    # cryptsetup luksFormat --type luks1 --use-random -S 1 -s 512 -h sha512 -i 5000 /dev/nvme0n1p3
    
  2. Decrypt the container and make it available at /dev/mapper/cryptlvm.

    # cryptsetup open /dev/nvme0n1p3 cryptlvm
    
  3. Create physical volume on the opened LUKS container.

    # pvcreate /dev/mapper/cryptlvm
    
  4. Create the volume group.

    # vgcreate vg /dev/mapper/cryptlvm
    
  5. Create the logical volumes. The size here is your personal preference.

    # lvcreate -L 40G vg -n swap
    # lvcreate -L 500G vg -n root
    # lvcreate -l 100%FREE vg -n home
    
  6. Format filesystems on each logical volume.

    # mkfs.ext4 /dev/vg/root
    # mkfs.ext4 /dev/vg/home
    # mkswap /dev/vg/swap
    
  7. Mount filesystems.

    # mount /dev/vg/root /mnt
    # mkdir /mnt/home
    # mount /dev/vg/home /mnt/home
    # swapon /dev/vg/swap
    
  8. Create FAT32 filesystem for the EFI system partition.

    # mkfs.fat -F32 /dev/nvme0n1p2
    
  9. Create mount point for EFI system partition at /efi.

    # mkdir /mnt/efi
    # mount /dev/nvme0n1p2 /mnt/efi
    
  10. Install the bare minimum packages.

    # pacstrap /mnt base linux linux-firmware mkinitcpio lvm2 neovim dhcpcd wpa_supplicant
    
  11. Generate fstab file.

    # genfstab -U /mnt >> /mnt/etc/fstab
    
  12. Change root into the new system.

    # arch-chroot /mnt
    [root@archiso /]#
    
  13. Set the /etc/localtime to you respective timezone.

    # ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime
    
  14. Generate /etc/adjtime.

    # hwclock --systohc
    
  15. Generate /etc/locale.conf. Uncomment en_US.UTF-8 UTF-8 in /etc/locale.gen and generate locale.

    # locale-gen
    # echo 'LANG=en_US.UTF-8' > /etc/locale.conf
    
  16. Create your hostname file.

    # echo yourhostname > /etc/hostname
    
  17. Add entries to hosts table.

    # nvim /etc/hosts
    
    127.0.0.1 localhost
    ::1 localhost
    127.0.1.1 yourhostname.localdomain yourhostname
    
  18. Add encrypt, lvm2 and resume hooks to /etc/mkinitcpio.conf NOTE: The order of hooks matters.

    # nvim /etc/mkinitcpio.conf
    ...
    ##   NOTE: If you have /usr on a separate partition, you MUST include the
    #    usr and fsck hooks.
    HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block encrypt lvm2 filesystems resume fsck)
    
  19. Recreate the initramfs image.

    # mkinitcpio -p linux
    
  20. Set the root password using passwd.

  21. Install GRUB boot loader.

    # pacman -S grub
    
  22. Install EFI boot manager.

    # pacman -S efibootmgr
    # grub-install --target=x86_64-efi --efi-directory=/efi
    
  23. Install microcode. grub-mkconfig will automatically detect microcode updates and configure accordingly. There's amd-ucode package for AMD CPUs.

    # pacman -S intel-ucode
    
  24. Embed a keyfile in initramfs to avoid having to enter the encryption passphrase twice (once for GRUB, once for initramfs.)

    # mkdir /root/secrets && chmod 700 /root/secrets
    # head -c 64 /dev/urandom > /root/secrets/crypto_keyfile.bin && chmod 600 /root/secrets/crypto_keyfile.bin
    # cryptsetup -v luksAddKey -i 1 /dev/nvme0n1p3 /root/secrets/crypto_keyfile.bin
    
  25. Add the keyfile to the initramfs image.

    # nvim /etc/mkinitcpio.conf
    FILES=(/root/secrets/crypto_keyfile.bin)
    
  26. Recreate the initramfs image.

    # mkinitcpio -p linux
    
  27. Configure GRUB. Set kernel parameter to unlock the LVM physical volume at boot using encrypt hook and allow hibernation to the swap space using resume hook. Pass the cryptkey file parameter you're going to generate later on.

    # nvim /etc/default/grub
    # GRUB boot loader configuration
    
    GRUB_DEFAULT=0
    GRUB_TIMEOUT=5
    GRUB_DISTRIBUTOR="Arch"
    GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet cryptdevice=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:cryptlvm resume=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx root=/dev/vg/root cryptkey=rootfs:/root/secrets/crypto_keyfile.bin"
    #GRUB_CMDLINE_LINUX
    
    # Preload both GPT and MBR modules so that they are not missed
    GRUB_PRELOAD_MODULES="part_gpt part_msdos"
    
    # Uncomment to enable booting from LUKS encrypted devices
    GRUB_ENABLE_CRYPTODISK=y
    

    You can get the required UUID using blkid.

    # blkid
    /dev/mapper/vg-swap: UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="swap"
    /dev/nvme0n1p3: UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="crypto_LUKS" PARTLABEL="Linux LUKS" PARTUUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    
  28. Generate GRUB's configuration files.

    # grub-mkconfig -o /boot/grub/grub.cfg
    
  29. Obtain the volume's major and minor device numbers from lsblk and echo it to /sys/power/resume.

    # lsblk  
    NAME          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINTS
    nvme0n1       259:0    0  1.8T  0 disk  
    ├─nvme0n1p1   259:1    0    1M  0 part  
    ├─nvme0n1p2   259:2    0  550M  0 part  /efi
    └─nvme0n1p3   259:3    0  1.8T  0 part  
    └─cryptlvm  254:0    0  1.8T  0 crypt 
        ├─vg-swap 254:1    0   40G  0 lvm   [SWAP]
        ├─vg-root 254:2    0  500G  0 lvm   /
        └─vg-home 254:3    0  1.3T  0 lvm   /home
    
    # echo 254:1 > /sys/power/resume
    
  30. Restrict /boot permissions.

    # chmod 700 /boot
    

At this point, you have a completely encrypted Arch Linux setup. DON'T reboot if you're not on Ethernet. You will lose the WiFi credentials from iwctl and it's impossible to install additional packages.

Post-installation

I'm always a GNOME fan so I'm going to install gnome as my Graphical User Interface. sway is another option but I will not put the install instructions here. Perhaps it's for another blog post.

  1. Create a non-root account.

    # useradd -m -G wheel,users -s /bin/bash username
    # passwd username
        New password: 
        Retype new password: 
        passwd: password updated successfully
    
  2. Install sudo.

    # pacman -S sudo
    
    # visudo
    ...
    ##
    ## User privilege specification
    ##
    root ALL=(ALL) ALL
    
    # Options
    Defaults editor=/usr/bin/nvim, !env_editor
    Defaults insults
    
    # Full Access
    username ALL=(ALL) ALL
    
    # Last rule as a safety guard
    username ALL=/usr/sbin/visudo
    
    # Uncomment to allow member of group wheel to execute any command
    %wheel ALL=(ALL) ALL
    ...
    
  3. Install GNOME.

    # pacman -S gnome dhclient iw dialog
    # pacman -Sy networkmanager network-manager-applet xf86-input-libinput
    
  4. Enable Gnome Display and Network Manager.

    # systemctl enable gdm
    # systemctl enable NetworkManager
    
  5. Exit chroot and unmount your filesystems.

    # exit
    # umount -R /mnt
    
  6. Finally, reboot.

    # reboot
    

Congratulations! You have survived Arch Linux installation.