VeproGames

In this tutorial, Arch Linux will be setup with BTRFS and almost Full Disk Encryption.

Obtain the ISO

If it’s not booting, check if:

Initial Setup

You are now at the prompt:

root@archiso ~ #

When in doubt, also conduct the Arch Linux Installation Guide: https://wiki.archlinux.org/title/Installation_guide and the Arch Linux Wiki: https://wiki.archlinux.org

If you want to erase what previously was on the device/drive, use dd or shred for HDDs, hdparm for SATA SSDs, or nvme for NVMe SSDs.

For this tutorial, we will install Arch Linux on /dev/sda. Replace this with your drive name.

Disk Names of HDDs and SSds are called sda, sdb, sdc and so on. For NVMe SSDs, it’s nvme0n1, nvme0n2 and so on. They are device files, a special type of file. In Linux, everything is a file.

You might want to erase the Partition Table first. A Partition Table describes where which filesystem lies on a drive. You can wipe it with wipefs -a /dev/sda.

You might want to connect to Wi-Fi. To find out the name of the interface, type ip a and find the interface name (mostly wlan0). Use iwctl to connect:

root@archiso ~ # iwctl
[iwd]# station wlan0 scan
[iwd]# station wlan0 get-networks
[iwd]# station wlan0 connect <Network name from Table above>

Run ping archlinux.org to check connection. Press Ctrl-C to cancel (any) command.

Partition the Disk

I recommend cfdisk to partition, it uses a TUI (Text User Interface) and is easier to use than fdisk, gdisk or parted (Fun Fact: If you want to automate partitioning, parted is the ideal tool).

Run cfdisk /dev/sda. If prompted, select gpt as partitioning scheme. dos (MBR) is legacy and the others are obscure.

Create the following partitions:

SizeTypeInfoResulting Partition (for /dev/sda)
1MBIOS bootAllows legacy devices to boot with this partitioning scheme/dev/sda1
512MEFI SystemThis is where Bootloaders go/dev/sda2
2G-4GLinux FilesystemThis will be where Kernels and initrds are stored. This will be unencrypted/dev/sda3
RemainingLinux FilesystemAll of the data, this will be encrypted/dev/sda4

Next, create the Filesystems. Without a Filesystem, files cannot be organized by the system.

Encrypt the Disk

Instead, create a LUKS Volume on /dev/sda4:

cryptsetup luksFormat /dev/sda4

Follow the insstructions. Choose a strong passphrase. Unlocking per TPM is possible, but out of scope of this tutorial.

Now, open the LUKS Volume:

cryptsetup luksOpen /dev/sda4 rootcrypt

A new device file will appear under /dev/mapper/rootcrypt.

BTRFS

Now, create a BTRFS on the mapped device (not /dev/sda4!, this would destroy the LUKS volume):

mkfs.btrfs /dev/mapper/rootcrypt

Mount the Filesystem on /mnt:

mount /dev/mapper/rootcrypt /mnt

Mounting opens the filesystem and “roots” it into the target directory (/mnt here). So basically, /dev/mapper/rootcrypt is accessible in /mnt now.

A great part of BTRFS are subvolumes. They differ in partitions in that they have no fixed size, thus are more flexible. Each subvolume can be snapshot individually.

Let’s create the following subvolumes:

Since parts in /var are relevant for snapshots, especially the pacman Database, it will be included in the root volume. Slightly larger snapshots are not grave, as BTRFS snapshots are smart and only store differences.

Note that the subvolume name (e. g. @) is independent of the actual place where it will be mounted (e. g. /). Where things will be mounted, will be decided by the filesystem table file fstab, more on that later.

Now that all subvolumes are created, we can unmount the /dev/mapper/rootcrypt device by just specifying the mountpoint (/mnt):

umount /mnt

Now, let’s mount the subvolumes:

mount -o noatime,compress=ztd,subvol=@ /dev/mapper/rootcrypt /mnt

This means: Mount the subvolume from /dev/mapper/rootcrypt on /mnt. Don’t modify modification and access times and compress created files using zstd.

Do this for the other volumes too:

mount --mkdir -o noatime,compress=ztd,subvol=@home /dev/mapper/rootcrypt /mnt/home

mount --mkdir -o noatime,compress=ztd,subvol=@.snapshots /dev/mapper/rootcrypt /mnt/.snapshots

When mounting deeper, manual mkdirs may be required:

mkdir -p /mnt/var/log

mkdir -p /mnt/var/ache/pacman/pkg

mount -o noatime,compress=ztd,subvol=@var_log /dev/mapper/rootcrypt /mnt/var/log

mount -o noatime,compress=ztd,subvol=@var_pkg /dev/mapper/rootcrypt /mnt/var/cache/pacman/pkg

Now, mount the boot and EFI System Partition (ESP):

mount --mkdir /dev/sda3 /mnt/boot

mount --mkdir /dev/sda2 /mnt/boot/efi

Now, everything is mounted.

Install the base system

pacstrap is used to install the base system. It installs the packages, and copies its keyring (used to sign packages) and mirrorlist over. (You can change the mirrorlist later, but I’ve always been good with the default).

Pacstrap the system; I recommend these base packages:

pacstrap -K /mnt base linux linux-lts linux-firmware btrfs-progs man networkmanager vim sudo

Optionally, you can add things like zsh (Z Shell), or the linux-zen kernel, if you prefer.

linux and linux-lts will be installed at once, this way, if one kernel causes trouble, you can boot the other.

Note that setting up propietary NVIDIA drivers needs extra steps with multiple kernels, this is not covered here.

We will install the bootloader later.

fstab

Next we need to generate the filesystem table file (fstab). The system will use this while booting to automatically mount everything needed.

Generate the fstab file for /mnt, and append (») it into /mnt/etc/fstab:

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

Don’t forget the -U! This makes it use UUIDs instead of device file names, which would cause problems if sda would be mounted later when more drives are connected and would become /dev/sdb, causing mounting (and startup) to fail.

Next remove all occurences of subvolid=xxx, since static IDs are not the best idea either and the subvol name is already given.

Setup and configure the system

Let’s arch-chroot into /mnt. You might know chroot. arch-chroot does all the –rbind stuff for us so /dev, /proc and /sys will be available in the chroot. Also, let’s use bash

arch-chroot /mnt /bin/bash

The prompt should change to:

[root@archiso /]#

Note that /mnt is now /, since we changed root.

Set the hostname by writing into /etc/hostname, either with a text editor like vim or echo and >.

Let’s set a root password:

passwd

Let’s generate the locales:

Now, set the timezone by symlinking the timezone file to /etc/localtime:

ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime

Fun fact: usr stands for “Unix System Resources”.

The Timezone file names follow the standardized format.

Lets edit the sudoers file. Run EDITOR=<your editor> visudo. Do not edit the file directly!

Uncomment the %wheel ALL=(ALL:ALL) ALL line.

Let’s add a regular user (e. g. nerd), create a home directory (-m), and give it access to sudo by adding the wheel group (-G stands for append extra groups) to them:

useradd -mG wheel nerd

Set their password:

passwd nerd

The Boot Loader

Last Step! Let’s install the bootloader. I will go with GRUB. To make GRUB work on UEFI systems, also install efibootmgr.

pacman -S efibootmgr grub

Let’s install grub:

grub-install /dev/sda

Grub should detect the platform (x86_64-efi) automatically. But, there are quirks to be aware of:

Some Motherboards have a weird UEFI implementation, causing NVRAM entries not to work correctly. If no boot device is detected after we are done, add --removable when running grub-install.

Other bootloaders you might be interested in: systemd-boot, rEFInd (requires some configuration to autodetect BTRFS volumes).

The Encryption again

Now we must configure more to finalize our encryption setup. First edit /etc/mkinitcpio.conf.

Add btrfs to BINARIES, so it looks like:

BINARIES=(btrfs)

Add encrypt after block in HOOKS, so it looks like (… is left out content):

HOOKS=(... block encrypt filesystems ...)

After saving the file, run:

mkinitcpio -P

So all initrds get regenerated with the encrypt hook.

Now, let’s make GRUB use the encrypt hook. Edit /etc/default/grub:

First, note the PARTUUID of the LUKS volume. Run blkid -o value -s PARTUUID /dev/sda4 (where the LUKS volume was created). The -o and -s means we only want to print the value with the tag PARTUUID

Protip: use :r!blkid -o value -s PARTUUID /dev/sda4 in vim or nvim to directly insert it into the editor

In the GRUB_CMDLINE_LINUX_DEFAULT, add: cryptdevice=PARTUUID=<the value we got>:rootcrypt root=/dev/mapper/rootcrypt

cryptdevice=… means that the LUKS Volume will be luksOpened to /dev/mapper/rootcrypt after the Passphrease was successfully input. root=… says where the partition with the / mountpoint resides.

While we’re at it, uncomment GRUB_DISABLE_SUBMENU=y, GRUB_SAVEDEFAULT=true and GRUB_DEFAULT=saved, so your decisions will be remembered.

Now generate the GRUB configuration:

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

At the very last, enable the networkmanager service: systemctl enable NetworkManager. When using Ethernet, you will have an Internet connection automatically on next boot, with Wi-Fi, run nmtui and configure your connection.

This should be all! Type exit to exit the chroot. Type umount -R /mnt to unmount everything. Type reboot and eject your bootable device.

After the Installation

It worked? Congrats! The next steps are the following:

Those are much more straightforward than what we did before. I won’t cover it here. I will probably make another article about this, especially regarding Wayland.

Tips

Notes