My install process

The key features of this setup are:

  • EFI (Extensible Firmware Interface) support, without legacy boot
  • Separate /boot and /efi partitions
  • LVM (Logical Volume Management) for easier volume resizing later
    • Separate /, /home and /var partitions
  • Encrypted boot device, with LUKS (Linux Unified Key Setup)
  • Users managed with homectl
  • systemd initramfs
  • Gnome 3
  • Flatpak for sandboxing applications

Pre-install checks

Ensure we've booted in EFI mode:

efivar -l

Prepare the live environment

First, identify network devices:

$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: wlp59s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DORMANT group default qlen 1000
    link/ether 48:f1:7f:f7:24:6b brd ff:ff:ff:ff:ff:ff

If you're working with Ethernet (unavailable in my case) this is fairly simple -- Arch will attempt to get an IP address over DHCP out of the box:

ip addr show <device>

It's a little more involved for WLAN, but still very much possible. First, set the regulatory domain:

iw reg set GB

Prepare a WPA supplicant configuration, then attempt to connect:

$ wpa_passphrase my-ssid my-passphrase >/etc/wpa_supplicant.d/my-ssid.conf
$ wpa_supplicant -i wlp59s0 -c /etc/wpa_supplicant.d/my-ssid.conf
Successfully initialized wpa_supplicant
Trying to associate with aa:aa:aa:aa:aa:aa (SSID='my-ssid' freq=2462 MHz)
Associated with aa:aa:aa:aa:aa:aa
wlan0: CTRL-EVENT-REGDOM-CHANGE init=COUNTRY_GB type=COUNTRY alpha2=GB
wlan0: WPA: Key negotiation completed with aa:aa:aa:aa:aa:aa [PTK=CCMP GTK=CCMP]
wlan0: CTRL-EVENT-CONNECTED - Connection to aa:aa:aa:aa:aa:aa completed [id=0 id_str=]

Sync the system time to ensure we don't get bitten by certificate validation issues:

timedatectl set-ntp true

Partitioning

List block devices:

lsblk

Partition the disks -- my installation will be on /dev/sda:

  • 1GB /efi system partition
  • 1GB /boot partition
  • Remainder of the disk for an LVM PV for /, /home, /var and swap
parted /dev/sda
(parted) mklabel gpt
(parted) mkpart ESP fat32 1MB 1001MB
(parted) set 1 esp on
(parted) mkpart Boot ext4 1001MB 2001MB
(parted) mkpart Data 2002MB 100%
(parted) print
(parted) quit

Prepare an encrypted container for the LVM PV:

cryptsetup luksFormat /dev/sda3

Open it:

cryptsetup open /dev/sda3 crypt_data

Set up the LVM PV, VG, and LVs:

  • /dev/sda3:
    • luke-banger VG:
      • 100GB / partition
      • 100GB /var partition
      • 16GB swap partition
      • Remainder of the VG for /home
pvcreate /dev/mapper/crypt_data
vgcreate luke-banger /dev/mapper/crypt_data
lvcreate -n root -L 100G luke-banger
lvcreate -n var -L 100G luke-banger
lvcreate -n swap -L 16G luke-banger
lvcreate -n home -l 100%FREE luke-banger

Now, create our filesystems:

  • FAT32 for /efi
  • ext4 for /boot if using Grub, else vfat for systemd-boot
  • ext4 for /, /var and /home
mkfs.fat -F32 /dev/sda1
mfs.ext4 /dev/sda2
mkfs.ext4 /dev/luke-banger/root
mkfs.ext4 /dev/luke-banger/var
mkfs.ext4 /dev/luke-banger/home

If using systemd-boot, note that it requires a vfat partition for /boot:

mkfs.vfat /dev/sda2

Create and enable our swap partition:

```console
mkswap /dev/luke-banger/swap
swapon /dev/luke-banger/swap

Check we're happy with the partition scheme:

lsblk

Performing the installation

Now, prepare the chroot we're installing to:

mount /dev/luke-banger/root /mnt
mkdir /mnt/{efi,boot,home,var}

mount /dev/sda1 /mnt/efi
mount /dev/sda2 /mnt/boot
mount /dev/luke-banger/home /mnt/home
mount /dev/luke-banger/var /mnt/var

Make sure we're happy with it:

mount | grep /mnt

Bootstrap the system with some packages:

pacstrap /mnt \
    base linux linux-firmware \
    cryptsetup lvm2 \
    e2fsprogs vim

Create /etc/fstab:

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

Finalising the installation

Switch to the chroot:

arch-chroot /mnt

Set the system timezone:

ln -sf /usr/share/zoneinfo/Europe/London /etc/localtime
hwclock --systohc --utc

Edit /etc/locale.gen to uncomment en_GB.UTF-8 UTF-8, then build locales:

locale-gen

Set the default locale:

echo 'LANG=en_GB.UTF-8' >/etc/locale.conf

Set the system hostname, and make it resolve:

echo 'luke-banger' >/etc/hostname
echo '127.0.0.1 luke-banger' >>/etc/hosts
echo '::1 luke-banger' >>/etc/hosts
echo '127.0.1.1 luke-banger.localdomain luke-banger' >>/etc/hosts

Configure sd-vconsole:

echo 'KEYMAP=uk' >/etc/vconsole.conf

Edit /etc/mkinitcpio.conf:

  • MODULES should contain dm_mod
  • HOOKS should contain, in this order:
    • base
    • systemd*
    • autodetect
    • keyboard*
    • sd-vconsole*
    • modconf
    • block
    • sd-encrypt*
    • lvm2*
    • filesystems
    • fsck

We need to create a crypttab configuration that'll be built into the initramfs, else our system will fail to boot because it can't find the root filesystem. First, copy /etc/crypttab to use as a template:

cp /etc/crypttab{,.initramfs}

Next, identify the PARTUUID for our root filesystem:

$ blkid /dev/sda3
/dev/sda3: UUID="00000000-0000-0000-0000-000000000000" TYPE="crypto_LUKS" PARTLABEL="Data" PARTUUID="22222222-2222-2222-2222-222222222222"

In this example our crypt_data container is located on /dev/sda3, with a partition UUID of 22222222-2222-2222-2222-222222222222. To save us having to type this, let's append it to the end of our newly created crypttab.initramfs:

blkid /dev/sda3 >>/etc/crypttab.initramfs

Edit the file to match the formatting of the template:

# Configuration for encrypted block devices.
# See crypttab(5) for details.

# <name>       <device>                                         <password>              <options>
crypt_data     PARTUUID=22222222-2222-2222-2222-222222222222    none

Finally, rebuild the initramfs:

mkinitcpio -P

Bootloader (Grub)

Install a bootloader:

pacman -S efibootmgr grub
grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=GRUB
grub-mkconfig -o /boot/grub/grub.cfg

Bootloader (systemd-boot)

Enable the bls_boot flag for /boot:

parted /dev/nvme0n1
(parted) toggle 2 bls_boot
(parted) quit

Install:

bootctl install --esp-path /efi --boot-path /boot

Add an entry for Arch Linux at /boot/loader/entries/arch.conf:

title    Arch Linux
linux    /vmlinuz-linux
initrd   /intel-ucode.img
initrd   /initramfs-linux.img
options  root=UUID=0399bbe8-8465-4b80-bdcd-754322f5c860 rw

And a fallback in /boot/loader/entries/arch-fallback.conf:

title    Arch Linux (fallback initramfs)
linux    /vmlinuz-linux
initrd   /intel-ucode.img
initrd   /initramfs-linux-fallback.img
options  root=UUID=0399bbe8-8465-4b80-bdcd-754322f5c860 rw

Final changes

Finally, set the root user's password:

passwd

Reboot.

Applying CPU microcode updates

For AMD systems:

pacman -S amd-ucode

For Intel systems:

pacman -S intel-ucode

Update the Grub configuration to include the new initrd:

grub-mkconfig -o /boot/grub/grub.cfg

Or edit /boot/loader/entries/arch.conf to add the additional initrd.

Configuring networking (NetworkManager)

We'll use the venerable NetworkManager, because that's what GNOME has support for.

pacman -S networkmanager
systemctl enable NetworkManager

Configuring networking (networkd; doesn't work)

Configure our network adapter by creating /etc/systemd/network/20-wired.network:

[Match]
Name=enp2s0f0

[Network]
DHCP=ipv4

Configure the network manager to start at boot:

systemctl enable systemd-networkd

For DNS resolution:

ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
systemctl enable systemd-resolved

Start it:

systemctl start systemd-resolved systemd-networkd

Check that it comes up:

networkctl status

Enable systemd-homed

It's already been installed as part of systemd, like it or not:

systemctl enable --now systemd-homed.service

Create your user account

Create the user:

homectl create --storage luks lukecarrier

Then make it show up in GDM:

cat <<EOF >/var/lib/AccountsService/users/lukecarrier
[User]
SystemAccount=false
EOF

Install sudo

pacman -S sudo

Configure the wheel group with visudo -f /etc/sudoers.d/wheel:

%wheel ALL = (ALL) ALL

Add users:

usermod -aG wheel lukecarrier

Setting up a graphical shell

pacman -S gnome-control-center gdm gnome-shell gnome-software power-profiles-daemon xdg-utils
systemctl enable gdm power-profiles-daemon

And some apps

pacman -S alacritty firefox flatpak

Install an AUR helper

I'm using paru:

sudo pacman -S --needed base-devel
git clone https://aur.archlinux.org/paru.git
cd paru
makepkg -si

Move to WirePlumber

sudo pacman -S wireplumber pipewire-pulse helvum

Graphical boot

Install Plymouth, and a patched GDM for graceful hand-off:

paru -S gdm-plymouth plymouth-git

Add it to the initrd in /etc/mkinitcpio.conf:

-HOOKS=(base systemd autodetect keyboard sd-vconsole modconf block sd-encrypt lvm2 filesystems fsck)
+HOOKS=(base systemd sd-plymouth autodetect keyboard sd-vconsole modconf block sd-encrypt lvm2 filesystems fsck)

And rebuild it:

mkinitcpio -P

Add the required kernel parameters in /etc/default/grub:

-GRUB_CMDLINE_LINUX=""
+GRUB_CMDLINE_LINUX="quiet loglevel=3 splash vt.global_cursor_default=0 systemd.show_status=auto rd.udev_log_level=3"

-#GRUB_GFXPAYLOAD_LINUX=keep
+GRUB_GFXPAYLOAD_LINUX=keep

And update the Grub configuration:

grub-mkconfig -o /boot/grub/grub.cfg

Install the Arch glow theme

Install it from AUR:

paru -S plymouth-theme-arch-glow

Enable it in /etc/plymouth/plymouthd.conf:

[Daemon]
Theme=arch-glow
ShowDelay=5
DeviceTimeout=8

Essential Shell extensions

These extensions add features that really feel core to the shell:

These ones could be good in the future with some polish:

  • Reorder Workspaces:
    • Default accelerators on Shell <= 42 ought to be Alt+Left and Alt+Right to match the workspace layout in the UI. It is configurable via extension settings.
    • Drag and drop workspaces in the activities overview? Space Bar can do this in the top bar.

Backlinks