Austin Morlan


Code Contact LinkedIn



Arch Linux - UEFI, systemd-boot, LUKS, and btrfs

Introduction


I recently purchased a new laptop (Dell XPS 13 9370) and needed to install Arch onto it. I thought I’d finally document the steps I took because I always seem to forget what I did the last time (one of the joys of Arch is that it rarely needs to be reinstalled).

There are a lot of helpful guides online about different installation setups, but I could never find one that met all of my requirements:

General


Create netctl interface for wifi:

cp /etc/netctl/examples/wireless-wpa /etc/netctl/wlp2s0-home

Edit wlp2s0-home to use the proper SSID and WPA key:

netctl start wlp2s0-home

Configure time:

timedatectl set-ntp true

Edit /etc/pacman.d/mirrorlist to prioritize local mirrors.

Partitioning and File System Creation


Use gdisk to create the boot partition and the main partition to be encrypted:

gdisk /dev/nvme0n1
o (Create a new empty GUID partition table (GPT))
Proceed? Y
n (Add a new partition)
Partition number 1
First sector (default)
Last sector +512M
Hex code EF00
n (Add a new partition)
Partition number 2
First sector (default)
Last sector (press Enter to use remaining disk)
Hex code 8300
w
Y

Set up the encryption container:

cryptsetup luksFormat /dev/nvme0n1p2
Are you sure? YES
Enter passphrase (twice)
cryptsetup open /dev/nvme0n1p2 luks

Format to FAT32 for the boot and btrfs for the root:

mkfs.vfat -F32 /dev/nvme0n1p1
mkfs.btrfs /dev/mapper/luks

Since I’d like to keep separate snapshots of home in case a root snapshot needs to be restored, I create a subvolume for both (see here for details). I also create one for /var so that its noisy state isn’t included in snapshots.

noatime and nodiratime are used to prevent a write every time a file or directory is accessed (not great for a COW filesystem like btrfs).

lzo is used for compression because it’s faster at the expense of disk space (of which I have plenty).

I don’t use discard because it has a performance cost: I just issue manual trim commands with fstrim.

mount /dev/mapper/luks /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@var
umount /mnt
mount -o subvol=@,ssd,compress=lzo,noatime,nodiratime /dev/mapper/luks /mnt
mkdir /mnt/{boot,home,var}
mount -o subvol=@home,ssd,compress=lzo,noatime,nodiratime /dev/mapper/luks /mnt/home
mount -o subvol=@var,ssd,compress=lzo,noatime,nodiratime /dev/mapper/luks /mnt/var
mount /dev/nvme0n1p1 /mnt/boot

Installation and Configuration


Install base Arch with some necessities:

pacstrap /mnt base base-devel btrfs-progs neovim sudo zsh zsh-autosuggestions zsh-completions zsh-syntax-highlighting intel-ucode wpa_supplicant

Generate fstab:

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

It should look something like this:

/dev/mapper/luks / btrfs rw,noatime,nodiratime,ssd,compress=lzo,subvol=@ 0 0
/dev/mapper/luks /home btrfs rw,noatime,nodiratime,ssd,compress=lzo,subvol=@home 0 0
/dev/mapper/luks /var btrfs rw,noatime,nodiratime,ssd,compress=lzo,subvol=@var 0 0
/dev/nvme0n1p1 /boot/efi vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro 0 2

Setting up other stuff:

cp /etc/netctl/wlp2s0-home /mnt/etc/netctl
cp /etc/pacman.d/mirrorlist /mnt/etc/pacman.d/mirrorlist
arch-chroot /mnt /bin/zsh
echo some_hostname > /etc/hostname
chsh -s /bin/zsh
ln -sf /usr/share/zoneinfo/US/Pacific /etc/localtime
hwclock --systohc
nvim /etc/locale.gen (uncomment en_US.UTF-8)
locale-gen
echo LANG=en_US.UTF-8 > /etc/locale.conf
passwd

Edit /etc/hosts:

127.0.0.1   localhost
::1     localhost
127.0.1.1   some_hostname.localdomain   some_hostname

Modify /etc/mkinitcpio.conf to add encrypt and btrfs:

HOOKS="base udev autodetect modconf block encrypt btrfs filesystems keyboard fsck"

And generate:

mkinitcpio -p linux

Then install systemd-boot:

bootctl --path=/boot install

Get UUID of cryptoLUKS partition:

blkid

Create /boot/loader/entries/arch.conf:

title Arch Linux
linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /initramfs-linux.img
options cryptdevice=UUID=UUID_FROM_ABOVE:luks:allow-discards root=/dev/mapper/luks rootflags=subvol=@ rd.luks.options=discard rw mem_sleep_default=deep

mem_sleep_default=deep is needed for my laptop to enter deep (S3) sleep.

Edit /boot/loader/loader.conf:

default arch

Reboot:

exit
umount -R /mnt
reboot

My Personal Preferences


After all of that, you should have a fully functioning Arch install. Everything from here on is just my own personal flavoring.

Set up lightdm with autologin (identity already proven with encryption password so why bother):

pacman -S lightdm lightdm-gtk-greeter accountsservice
systemctl enable lightdm
groupadd -r autologin
useradd -m -g users -G wheel,autologin -s /bin/zsh austin
passwd austin

Edit /etc/lightdm/lightdm.conf:

[Seat:*]
autologin-user=austin

Add user to sudo:

visudo

Uncomment and log in as user:

%wheel ALL=(ALL) ALL
exit

Install Intel GPU and laptop stuff:

sudo pacman -S xf86-video-intel xorg-server xf86-input-libinput

Install more useful packages:

sudo pacman -S ttf-dejavu gnome-terminal pulseaudio pavucontrol firefox
openssh git

Install i3:

sudo pacman -S i3-gaps i3status rofi

Reboot into i3:

sudo reboot

Automatic wireless connect with netctl-auto:

sudo systemctl enable netctl-auto@wlp2s0
sudo systemctl start netctl-auto@wlp2s0

Correcting Errors


If something went wrong and you need to get back in from the live image:

cryptsetup open /dev/nvme0n1p2 luks
mount -o subvol=@,ssd /dev/mapper/luks /mnt
mount -o subvol=@home,ssd /dev/mapper/luks /mnt/home
mount -o subvol=@var,ssd /dev/mapper/luks /mnt/var
mount /dev/nvme0n1p1 /mnt/boot
arch-chroot /mnt /bin/zsh

Sources


1 2 3