Arch Linux installation notes: three firesystem schemes

I started my Linux journey with Arch Linux about five years ago (Technically, I used Ubuntu 9.10 way back when, but that's a story for another day). As a newbie, installing Arch by hand was a pretty big deal for me. It taught me almost everything about Linux and open source software in general.

Overtime, I moved on from Arch to Debian/Ubuntu/Fedora, but I always keep a technical note on how to install Arch Linux. What drives me to revisit this topic? Well, because I decided to put Linux on an old MacBook Pro with Intel CPU. I can think of no better distro than Arch Linux: it is flexible, lightweight, and... did I mention it's Arch, btw?

This article focuses on installing Arch Linux base system on a laptop or desktop with a single hard drive, and with UEFI support. It uses one of three partition/firesystem schemes and one of two boot loaders (GRUB or systemd-boot). The scenarios are:

  1. LVM with ext4: no encryption
  2. LVM on LUKS: offers root partition encryption
  3. Btrfs on LUKS: above, and btrfs
  4. Encrypted EFI system partition with Unified Kernel Image

The purpose is to dual boot Arch Linux with MacOS, so encrypted EFI partition is out of the question here. I might write another article in the future about Unified Kernel Image.

When researching and refining my notes, I came across YouTube channel EF linux. He was such a great guy, concise and straight to the point. I also recommend his video about btrfs snapshot with timeshift.

So, without further ado, let me present my raw notes of installing Arch Linux in (late) 2023.


Live system stage

Preparation

wireless network config
Wi-Fi: iwctl (authenticates to Wi-Fi) or wifi-menu (netctl)
Ethernet: ArchISO's systemd-networkd and systemd-resolved should work out of the box

SSH remote install:
passwd to set root password
systemctl start sshd.service
ip addr to get IP address

Optional:
setfont ter-132b set larger font for HiDPI
timedatectl set-ntp true to ensure the system clock is accurate
ls /sys/firmware/efi/efivars verify boot mode (BIOS or UEFI)
cat /sys/firmware/efi/fw_platform_size another way to verify (64 or 32)

Partitioning

https://wiki.archlinux.org/title/Partitioning
https://wiki.archlinux.org/title/EFI_system_partition
https://wiki.archlinux.org/title/Btrfs
https://wiki.archlinux.org/title/Install_Arch_Linux_on_LVM
https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system

Boot partition

Partition the disk: create ESP (EFI system partition) and "Linux root" partition
cfdisk is TUI of fdisk
fdisk -l check existing disks/partitions
fdisk /dev/sd[X]

Format and mount:
mkfs.fat -F 32 /dev/sda1 format ESP to FAT32
mkdir -p /mnt/boot
mount /dev/sda1 /mnt/boot

Notes on ESP mount point:

  • /boot: cannot be encrypted; contains kernels, initramfs images, microcode, boot loader config files; supports dual boot with Windows/MacOS
  • /efi (historically /boot/efi): only boot loader config files
Mount point Partition Partition type GUID Size
/boot or /efi /dev/sda1 EFI system partition C12A7328-F81F-11D2-BA4B-00A0C93EC93B 300MB to 1GB
/ /dev/sda2 Linux root 4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709 remainder

1. LVM

LVM with ext4 (no LUKS encryption), see Install Arch on LVM

  • create pv, vg and lv on /dev/sda2 (if lv will be formatted with ext4, leave 256 MiB space for e2scrub; see next section on how to)
  • format mkfs.ext4 /dev/VolGroup/root
  • mount mount /dev/VolGroup/root /mnt
  • note: swap and home logic volumes are optional

2. LVM on LUKS

LVM on LUKS

  • LUKS2
    cryptsetup luksFormat /dev/sda2
    cryptsetup open /dev/sda2 cryptroot
  • LVM
    pvcreate /dev/mapper/cryptroot
    pvdisplay/pvscan
    vgcreate VolGroup /dev/mapper/cryptroot
    lvcreate -L 100%FREE VolGroup -n root
    lvreduce -L -256M VolGroup/root ### if ext4, leave 256 MiB space for e2scrub
  • format and mount
    mkfs.ext4 /dev/VolGroup/root
    mount /dev/VolGroup/root /mnt

3. Btrfs on LUKS

Btrfs

  • LUKS2
    cryptsetup luksFormat /dev/sda2
    cryptsetup open /dev/sda2 cryptroot
  • Btrfs
    mkfs.btrfs -L archlinux /dev/mapper/cryptroot
    mount /dev/mapper/cryptroot /mnt
    cd /mnt
    btrfs subvolume create @            ## or root
    btrfs subvolume create @home   ## or home
    cd
    umount /mnt
    mkdir /mnt/home
    mount -o subvol=@,compress=zstd /dev/mapper/cryptroot /mnt
    mount -o subvol=@home,compress=zstd /dev/mapper/cryptroot /mnt/home

Install base system

(optionally) edit mirrors /etc/pacman.d/mirrorlist
pacstrap -K /mnt base linux linux-firmware amd/intel-ucode sudo lvm2 btrfs-progs nano optionally networkmanager

  • Kernels can be linux-lts or linux-zen
  • skip linux-firmware if it's a VM

FSTAB

genfstab -U /mnt >> /mnt/etc/fstab use -U or -L to define by UUID or labels, respectively
cat /mnt/etc/fstab to verify

Chroot stage

arch-chroot /mnt

Initramfs (mkinitcpio)

Workflow:
edit hooks in/etc/mkinitcpio.conf
re-generate mkinitcpio -P

See also:
mkinitcpio common hooks
kernel parameters

1. LVM

lvm2 package must be installed in the arch-chroot environment
"udev" and "lvm2" for busybox-based initramfs: HOOKS=(base udev ... block lvm2 filesystems)
"systemd" and "lvm2" for systemd-based initramfs: HOOKS=(base systemd ... block lvm2 filesystems)

2. LVM on LUKS

lvm2 package must be installed in the arch-chroot environment
"keyboard", "encrypt" and "lvm" for busybox-based initramfs: HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block encrypt lvm2 filesystems fsck)
"keyboard", "sd-encrypt" and "lvm" for systemd-based initramfs: HOOKS=(base systemd autodetect modconf kms keyboard sd-vconsole block sd-encrypt lvm2 filesystems fsck)

3. Btrfs on LUKS

btrfs-progs package must be installed in the arch-chroot environment
"keyboard" and "encrypt" for busybox-based initramfs
"keyboard" and "sd-encrypt" for systemd-based initramfs

For single device btrfs pool, "filesystem" hook is sufficient (no need for "btrfs" hook)
For multi device btrfs pool, use one of "udev", "systemd" or "btrfs" hooks. See common hooks

Additionally, edit /etc/fstab to add mount options: (get UUID by lsblk -f or blkid)

UUID=XXX / btrfs subvol=@,compress=zstd:9,discard=async,noatime,ssd
UUID=YYY /home btrfs subvol=@home,compress=zstd:9,discard=async,noatime,ssd

Boot loader

Installation:

  • systemd-boot is shipped with the systemd package which is a dependency of the base meta package
  • GRUB pacman -S grub efibootmgr
  • rEFInd: pacman -S refind-efi efibootmgr

Kernel parameters references:

1. LVM

Choose any boot loader
Kernel parameter root=/dev/VolGroup/root

2. LVM on LUKS

Grub install (assuming esp is /boot)
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB
grub-mkconfig -o /boot/grub/grub.cfg

(Optional) fallback boot path:
either use --removable flag
or mkdir *esp*/EFI/BOOT and cp *esp*/EFI/GRUB/grubx64.efi *esp*/EFI/BOOT/BOOTX64.EFI

Kernel parameters: https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system#Configuring_the_boot_loader_2
Get UUID by lsblk -f or blkid
Unlock encrypted root partition at boot: (get device-UUID refers to LUKS pratition /dev/sda2)
For encrypt hook: cryptdevice=UUID=<device-UUID>:cryptroot:allow-discards root=/dev/VolGroup/root
For sd-encrypt hook: rd.luks.name=<device-UUID>=cryptroot rd.luks.options=discard root=/dev/VolGroup/root

3. Btrfs on LUKS

Install systemd-boot: bootctl install optionally set --esp-path=/custom/esp
Automatic update: enable systemd-boot-update.service and/or add pacman hook

Configure nano /boot/loader/loader.conf

# default name must match filename /boot/loader/entries/arch.conf
default arch
timeout 3
console-mode max
# console-mode auto/keep
# editor no

Add loaders nano /boot/loader/entries/arch.conf add -lts for LTS kernel

title Arch Linux
linux   /vmlinuz-linux
initrd  /intel-ucode.img
# initrd  /amd-ucode.img
initrd  /initramfs-linux.img
# kernel parameters for btrfs on LUKS ("encrypt" hook), where XXX is /dev/sdb2, YYY is /dev/mapper/cryptroot
options cryptdevice=UUID=XXX:cryptroot:allow-discards root=/dev/mapper/VolGroup-root rw quiet splash
# kernel parameters for btrfs on LUKS ("sd-encrypt" hook), where XXX is /dev/sdb2, YYY is /dev/mapper/cryptroot
options rd.luks.name=XXX=cryptroot rd.luks.options=discard root=UUID=YYY rootflags=subvol=@ rw quiet splash

Note:

  • Fedora GRUB only has "rd.luks.name=", no "root=" nor "rootflags="; but Arch has to have these
  • Either set "rootflags=" here or btrfs subvolume set-default <subvolume-id> /

Fallback nano /boot/loader/entries/arch-fallback.conf; add -lts for LTS kernel

title Arch Linux (fallback initramfs)
...
initrd  /initramfs-linux-fallback.img
...

Time zone

From here on is easy, just follow Installation Guide

ln -sf /usr/share/zoneinfo/Canada/Toronto /etc/localtime to set timezone
hwclock -w -u to set time

Localization

nano /etc/locale.gen uncomment en_CA.UTF-8 and other needed locales
or
echo "en_CA.UTF-8 UTF-8" >> /etc/locale.gen
lastly
locale-gen to generate locale

nano /etc/locale.conf to set the LANG variable: LANG=en_US.UTF-8
or
optionally locale > /etc/locale.conf

Network configuration

echo MYHOSTNAME > /etc/hostname

nano /etc/hosts

127.0.0.1   localhost
::1     localhost
127.0.1.1   MYHOSTNAME.localdomain  MYHOSTNAME

either systemctl enable systemd-networkd.service systemd-resolved.service and follow some example configurations
or pacman -S networkmanager + systemctl enable NetworkManager

User and password

passwd for root We want passwordless root
ensure sudo package is installed
useradd -m -G wheel -s /bin/bash your_user
passwd your_user
EDITOR=nano visudo uncomment %wheel All=(All) All

Reboot

exit to exit chroot
umount -R /mnt optional but safe
reboot now

Post-install

Useful topics

systemd-boot: enable systemd-boot-update.service and/or add pacman hook

zram: replaces swap file or swap partition

Hibernation: (swap partition)
For "encrypt" hook: resume=/dev/VolGroup/swap (same format as root parameter)
systemd-boot ("sd-encrypt" hook): does not require additional kernel parameter with systemd >= v255

Snapper does not have command line tool; but has GRUB and rEFInd integration
Timeshift has a GUI as well as a command line tool