User:Drack/SystemInstallation
System Installation
Arch Linux wiki provides two guides for installing an operating system:
Here is a summary of the needed steps to install a system that suits my need.
System-land
Medium preparation
Image download and installation medium creation
First, download the .iso image from an HTTP mirror and check the checksum:
cd /tmp wget https://archlinux.mirrors.ovh.net/archlinux/iso/2024.03.01/archlinux-2024.03.01-x86_64.iso sha256sum archlinux-2024.03.01-x86_64.iso
Then, create a [bootable USB key](disk.html) with the .iso image. Once done, boot the live environment with [Secure Boot](security.html) disabled as it not supported by the Arch installation medium. The live environment should display a GRUB menu, entering then a root@archiso prompt. Start a tmux session to work easily with terminals during the installation process.
Console configuration
List available console keymaps and set wanted keyboard layout:
ls /usr/share/kbd/keymaps/**/*.map.gz loadkeys fr-pc # [fr is not supporting "é" | fr-latin1 | fr-latin9 | azerty]
Boot checking
Verify the boot mode checking the UEFI bitness:
cat /sys/firmware/efi/fw_platform_size
Depending on the returned value:
- 64 → x64 UEFI.
- 32 → 32-bit IA32 UEFI, which will limit the boot loader choice to GRUB.
- Not exist → system may be booted in BIOS (or CSM) mode. If you have a UEFI/GPT system, it will rise a problem during the boot loader installation as GRUB will not use efibootmgr to create a UEFI boot entry pointing to it.
Verify the Secure Boot state and presence of cryptoprocessor:
bootctl | grep "Secure Boot" bootctl | grep "TPM2"
Check that Secure Boot is disabled and that TPM2 is supported for complex setup with btrfs, LUKS, UKI, Secure Boot and TPM (See section 1.1.3).
Internet and time configuration
[Connect to the Internet](network.html), where the simplest method is using an Ethernet cable, where we just have to verify that our interface is listed and use dhclient to obtains an IP address. Or we can also use the shipped iwd to connect to a Wi-Fi network. Once connected to the network, one can enable the [OpenSSH](remote.html) service (and set a password for root) from the live system to access it remotely from another computer.
Local timezone should be synced automatically once a connection to the internet is established. You can check, or set it manually using:
timedatectl set-timezone Europe/Paris
Choice of installation scenario
One can choose one of the following scenarios, including disk partitioning and formatting:
- Simple setup with ext4 and GRUB (See section 1.1.2)
- Complex setup with btrfs, LUKS, UKI, Secure Boot and TPM (See section 1.1.3)
Stage 1 – Simple setup
This is a simple scenario without logical volume management, without encryption, without authentication and integrity of the boot process, and with an easy installation of the traditional GRUB bootloader. Typically used for a home desktop computer, were no strong security is needed while being easily compatible with all hardware (BIOS or UEFI, MBR or GPT), features (e.g., hibernation) and repairable with traditional tools.
The following show a summary of the achieved layout:
Mount point | Partition | Partition type GUID [fdisk code] | Filesystem | Suggested size |
/mnt/boot | /dev/efi_partition | [EFI System Partition (ESP)](../../notes/boot.html) [1] | FAT32 (vfat) | Around 512 MiB |
[SWAP] | /dev/swap_partition | Linux swap [19] | ext4 | At least RAM size |
/mnt | /dev/root_partition | Linux x86-64 root (/) [23] | ext4 | At least 15 GiB |
/mnt/home | /dev/home_partition | Linux home (/home) [42] | ext4 | Remainder of the device |


Disk partitioning
The first step is to partition the disk. Optionally, one can create a [RAID](disk.html) before this step, notably if multiple disks needs to be used as a single one. At least the following partitions are required for a computer:
- One partition for the root directory /.
- An [EFI System Partition (ESP)](../../notes/boot.html) for booting in UEFI mode. If the disk already has an ESP, do not create another one but use the existing partition instead.
Here, we make the following choices:
- Use of UEFI for booting and GPT as partition table with traditional partitions.
- We ensure the size of the ESP is enough to hold multiple kernel versions.
- We ensure the size of the SWAP is enough to save RAM for hibernation.
- We ensure the size of the root partition is enough to hold a full system.
- We mount the ESP at /boot for easiest administration.
See [disk partitioning](disk.html) for details, but one can achieve the layout presented in Table 1 using [fdisk](disk.html) or [gdisk](disk.html).
Partition formatting
Once done, you will have to format the partitions. Here, we will demonstrating it using [FAT](disk.html) for the [ESP](../../notes/boot.html) and [ext4](disk.html) filesystems for system and user data:
mkfs.fat -F 32 /dev/efi_partition # Only if it has been newly created. mkswap /dev/swap_partition mkfs.ext4 /dev/root_partition mkfs.ext4 /dev/home_partition
Our partitions are ready to be mounted and enabled, they will automatically be detected later by genfstab:
mount --mkdir /dev/root_partition /mnt mount --mkdir /dev/home_partition /mnt/home mount --mkdir /dev/efi_partition /mnt/boot swapon /dev/swap_partition
Stage 1 – Complex setup
This setup is inspired of:
This is an advanced scenario with:
- Logical volume management through [BtrFS](disk.html).
- Full disk encryption though [LUKS](security.html) and [device-mapper (dm)](linux_kernel.html)'s dm-crypt.
- Bootloader-less installation leveraging [Unified Kernel Image (UKI)](linux_kernel.html).
- Boot process authenticity and integrity using [Secure Boot](security.html) and [TPM](../../notes/boot.html).
- Hibernation support with [Initial RAMDisk (initramfs)](linux_kernel.html) in Systemd mode.
Typically used for traveling laptop, it provides performance and strong security, but requires recent hardware for the TPM, some features may be harder to configure, and specialized tool must be used to repair the system.
In the following, we will assume that /dev/sda is the block device that will hold our disk layout. If an installation spanning on multiple disk is needed, setup the [RAID](disk.html) in the first place and use the new mapped device instead of /dev/sda. The following show a summary of the achieved layout:
Mount point (w/o chroot) | Partition | Function | Partition type GUID [gdisk code] | Filesystem | Suggested size |
/mnt/efi | /dev/sda1 | EFI partition | [EFI System Partition (ESP)](../../notes/boot.html) [ef00] | FAT32 (vfat) | Around 512 MiB |
/dev/mapper/rootfs | /dev/sda2 | LUKS partition | Linux LUKS [8309] | LUKS | Remainder of the device |
Mount point (w/o chroot) | Partition | Function | Partition type GUID [gdisk code] | Filesystem | Suggested size |
/mnt | /dev/mapper/rootfs | Btrfs partition | Linux x86-64 root (/) [8304] | btrfs | Remainder of the device |
Mount point (w/ chroot) | Subvolume | Type |
/ | @ | btrfs |
/home | @home | btrfs |
/var | @var | btrfs |
/swap | @swap | SWAP |


TODO: Should I add a dedicated subvolume @storage mounted in /home/storage?
Disk partitioning and formatting for ESP and LUKS
The first step is to format our disk to hold the [EFI System Partition (ESP)](../../notes/boot.html) and our [Linux Unified Key Setup (LUKS)](security.html) container. The mountpoint for the ESP is /efi instead of /boot. It is necessary since, by choosing /boot as the ESP, the traditional /boot files such as the kernel image and the initramfs will resides on the ESP instead of the root Btrfs subvolume (@). Therefore, they will not be able to be included in the subvolume snapshot and restored from backup. This choice also allows to encrypt /boot.
One can see [disk partitioning](disk.html) for details on how to achieve the layout presented in Table 2, but in summary:
- Partition the disk with [gdisk](disk.html) and create the two aforementioned partitions:
gdisk /dev/sda # o # n # ENTER # ENTER # +512M # ef00 # n # ENTER # ENTER # ENTER # 8309 # w
- Format the [ESP](../../notes/boot.html) using [FAT](disk.html):
mkfs.vfat -F 32 -n ESP /dev/sda1
- Format (create) the [LUKS](security.html) container, choose a passphrase, and mount it (open) with the rootfs device mapper name:
cryptsetup --type luks2 luksFormat /dev/sda2 cryptsetup open /dev/sda2 rootfs
Disk partitioning and formatting for Btrfs
Our LUKS device-mapper is now available at /dev/mapper/rootfs and is ready to be formatted as a [BtrFS](disk.html) filesystem:
mkfs.btrfs -L rootfs /dev/mapper/rootfs
For now, it is not necessary to use any special options to mount the root partition. Mount our Btrfs root partition under /mnt to manage its subvolumes:
mount --mkdir /dev/mapper/rootfs /mnt
Subvolumes partitioning
Our Btrfs root partition is now available at /mnt and is ready to be logically partitioned using subvolumes. Create several subvolumes:
- @ for / such that we can snapshot the system state (including /boot files).
- @home for /home such that we can snapshot the user data and configuration.
- @var for /var such that it is not included in @ snapshots – lots of useless write operations and noisy state.
- @swap for [SWAP] such that we can have an encrypted SWAP file.
btrfs subvolume create /mnt/@ btrfs subvolume create /mnt/@home btrfs subvolume create /mnt/@var btrfs subvolume create /mnt/@swap
Now that our subvolumes are created, unmount the Btrfs root partition, which will not be needed anymore unless it is needed to perform Btrfs subvolume management:
umount /mnt
We can now mount our root subvolume first. Then, we can mount the other previously created subvolumes as well as the ESP under the root subvolume:
mount --mkdir -o noatime,nodiratime,compress=zstd,subvol=@ /dev/mapper/rootfs /mnt mount --mkdir -o noatime,nodiratime,compress=zstd,subvol=@home /dev/mapper/rootfs /mnt/home mount --mkdir -o noatime,nodiratime,compress=zstd,subvol=@var /dev/mapper/rootfs /mnt/var mount --mkdir -o noatime,nodiratime,compress=zstd,subvol=@swap /dev/mapper/rootfs /mnt/swap mount --mkdir /dev/sda1 /mnt/efi
Note that we use [optimization flags](disk.html) for compression and access time bypass for Btrfs subvolumes.
SWAP formatting
Instruct Btrfs to create a swap file (remember to adjust its size) and activate it using [/usr/share/man/man8/swapon.8.gz swapon]:
btrfs filesystem mkswapfile --size 16g --uuid clear /mnt/swap/swapfile swapon /mnt/swap/swapfile
The mounting points and their flags will automatically be detected later by genfstab.
System bootstrapping
Package bootstrapping
Use the pacstrap script to install packages inside the root partition:
- Install the base package, the Linux kernel, and firmware for common hardware, installing only the very minimal system:
pacstrap -K /mnt base linux linux-firmware
- Stopping here would be limited, if it cannot connect to the internet, edit files or compile packages. Hence, we also add network tools, basic text editors, base packages for compilation (e.g. gcc, make), terminal multiplexer, the GRUB boot loader, UEFI management tools, and the [BtrFS](disk.html) filesystem:
pacstrap -K /mnt dhclient iwd networkmanager pacstrap -K /mnt nano vi vim pacstrap -K /mnt base-devel less man man-pages pacstrap -K /mnt tmux pacstrap -K /mnt grub pacstrap -K /mnt efibootmgr efitools sbctl pacstrap -K /mnt btrfs
- If you have an Intel or AMD CPU, enable microcode updates in addition:
pacstrap -K /mnt amd-ucode # For AMD CPUs. pacstrap -K /mnt intel-ucode # For Intel CPUs.
To make our drives automatically mounted in the new system, generate an fstab file (use -U or -L to define path by UUID or labels, respectively) representing the current mounting under /mnt:
genfstab -U /mnt >> /mnt/etc/fstab
Now, chroot into the new system:
arch-chroot /mnt
From here, follow the correct stage 2 guide according to the scenario chosen before, either the simple setup (See section 1.1.5) or the complex setup (See section 1.1.6).
Stage 2 – Simple setup
Bootloader installation
Once chrooted in the new system, we will install a Linux-capable boot loader on the ESP, here [GRUB](../../notes/boot.html). Refer to the dedicated section for details about the installation, but in summary, execute the following for a UEFI-based system:
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub grub-mkconfig -o /boot/grub/grub.cfg
Our system is ready to boot now.
Stage 2 – Complex setup
Initramfs configuration for LUKS
We need to allow the [Initial RAMDisk (initramfs)](linux_kernel.html) image to:
- Mount the ESP partition which is [FAT](disk.html).
- Decrypt a LUKS encrypted block device – by asking the passphrase to the user or fetching it from the TPM.
- Mount a btrfs subvolume as root filesystem.
Since all of this has to be done in the early userspace, we need to execute appropriate hooks for the additional features (keyboard handling, decryption handling, filesystem access drivers). Asking for the LUKS password in the early userspace is possible with the initramfs in the init mode (from busybox), but not fetching the LUKS password from the TPM. To do so, we need to use the systemd mode since we will use systemd-cryptenroll for the TPM management later.
Configure the /etc/mkinitcpio.conf file by ensuring and/or add the following hooks while removing the udev hook: systemd, keyboard, sd-vconsole, sd-encrypt, filesystems (incl. btrfs). It may differ but should look like to:
HOOKS=(base systemd autodetect modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)
Configure the /etc/mkinitcpio.conf file by ensuring and/or add the following modules: vfat. It may differ but should look like to:
MODULES=(fat vfat)
Then, regenerate the initramfs image:
mkinitcpio -P
Creation of the UKI
We will use [mkinitcpio](arch_linux.html) to create the [Unified Kernel Image (UKI)](linux_kernel.html).
First, store the appropriate kernel's [command-line parameters](linux_kernel.html) in the /etc/kernel/cmdline file, allowing the UKI to find and mount the root system. Here, we use the systemd version of the kernel command-line parameters for LUKS decryption using rd.luks.name:
rd.luks.name=DEVUUID=rootfs root=/dev/mapper/rootfs rootflags=subvol=@
Where:
- DEVUUID is the UUID of the block device containing the LUKS container, which can be found using:
lsblk -o UUID /dev/sda2 | tail -n 1
- rootfs is the device mapper name used above.
- @ is the Btrfs root subvolume name.
Note that since we use Secure Boot, those command-line parameters will not be able to be changed from the UEFI boot manager or interactively – because signed and embedded in the UKI.
Then, we will have to configure mkinitcpio for the [generation of an UKI](arch_linux.html). In such, set the following in the default linux preset of mkinitcpio located at [file:///etc/mkinitcpio.d/linux.preset /etc/mkinitcpio.d/linux.preset]:
default_uki="/efi/EFI/Linux/arch-linux.efi" # Optionnal. # If you want an additional boot entry to a fallback initramfs to add later: fallback_uki="/efi/EFI/Linux/arch-linux-fallback.efi"
Then, re-generate the preset to create the UKI on the ESP:
mkdir -p /efi/EFI/Linux mkinitcpio -p linux
Thanks to the default mkinitcpio hooks, the UKI will be regenerated by a [Pacman hook](arch_linux.html) at appropriate times after upgrading.
Boot manager configuration
We do not use any third-party software bootloader in this setup, since we leverage the UEFI ability to load EFI binaries and use an UKI acting as an EFI binary. The only needed configuration is to create an entry in the boot manager using [efibootmgr](../../notes/boot.html) loading the UKI located on /dev/sda1:
efibootmgr --create --disk /dev/sda --part 1 --label "archlinux" --loader '\EFI\Linux\arch-linux.efi' --unicode
System configuration
We can now configure various little aspects of the system:
- Set the time zone and run hwclock to generate /etc/adjtime:
ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime hwclock --systohc # If you need to manually configure the system and hardware clock/time/date after a CMOS reset: # sudo hwclock --set --date='2023-10-06 17:47' # sudo hwclock --hctosys
- Configure /etc/locale.gen to enable the desired locales (time, date, currency, etc.), then generate the configured locales:
cat /etc/locale.gen echo "fr_FR.UTF-8 UTF-8" > /etc/locale.gen locale-gen
Then, create the /etc/locale.conf file and set the LANG variable accordingly to activate the desired and generated locale:
echo "LANG=fr_FR.UTF-8" > /etc/locale.conf
Make the console keyboard layout changes persistent in /etc/vconsole.conf:
echo "KEYMAP=fr-pc" > /etc/vconsole.conf
Make the X11 keyboard layout changes persistent using [localectl](setup.html):
localectl set-x11-keymap fr
- Create the hostname file:
echo "citadel" > /etc/hostname
- Enable the [fstrim](optimization.html) timer and service if you have at least one SSD:
systemctl enable --now fstrim.timer
- Set the root password:
passwd
Exit the chroot environment by typing exit or pressing Ctrl+d. Optionally manually unmount all the partitions:
swapoff -a umount -R /mnt
Finally, restart the machine by typing reboot. Any partitions still mounted will be automatically unmounted by systemd. Remember to remove the installation medium and then login into the new system with the root account.
Stage 3 – Complex setup
If the system has been able to reboot correctly and the passphrase for the LUKS container has been asked to the user, everything is correctly configured. We can finally sign our binaries and enroll our keys.
Secure Boot enrolling
It is now time to establish the cryptographic verification between the UEFI and the kernel through the Secure Boot mechanism and the UKI.
First, backup EFI variables (keys and certificates) in case of error:
for var in PK KEK db dbx; do efi-readvar -v $var -o uefi_backup_${var}.esl; done
Check the Secure Boot status and ensure it is in Setup Mode, when the Platform Key is removed. If not, enter the UEFI firmware setup and deletes / clears the keys and certificates.
sbctl status
We will create our custom secure boot keys and enroll them alongside the Microsoft's keys shipped with the motherboard (ensuring not bricking the device, see [1]):
sbctl create-keys sbctl enroll-keys -m
If a File is ummutable error is encountered, simply execute the following command against the specified file:
chattr -i FILE
It will allows for the sbctl command writing to those files – being UEFI variables exposed through sysfs by the kernel. Check the Secure Boot status again, and ensure the Setup Mode is disabled, hence being in User Mode. If so, Secure Boot will be able to check the UKI integrity using our keys.
User-land
User management
First, create a new user that will be the main user of the machine, set its password and its home directory:
useradd -m $username passwd $username mkdir -p /home/$username usermod -d /home/$username -m $username
Allow this user to run root commands by making him a sudoer:
pacman -S sudo groupadd sudo usermod -aG sudo $username
And don't forget to uncomment the %sudo ALL=(ALL:ALL) ALL line in /etc/sudoers file.
Package management
Then, we need to [connect to the Internet](network.html) just like above to continue installing new packages. Update the Pacman database:
pacman -Sy
You can then install the graphical stack:
- My video server.
- My window manager.
- Required to run demanding applications (e.g., [Nvidia](linux_kernel.html) or [Intel Graphics](linux_kernel.html)).
- [GTK from GNOME](unix.html) and [Qt from KDE](unix.html).
You can then install the network stack:
- My network manager.
- Required to run some specific network interfaces.
You can then install the sound stack:
- The kernel sound card driver.
- The main multimedia framework and sound server.
You should have now a system ready to use that can be compared to an automatic installer in other distros. You can now install user applications, like web browsing and mail, file synchronization, editors, shells and terminals, etc.:
- Text editor and LISP machine.
- Web browser and bookmarks synchronizer.
- Terminal with Alacritty, multiplexer with Tmux, shell with ZSH.
- VCS with Git, local monitoring with GR, real-time synchronization with Syncthing.
- Remote access with SSH and SSHFS, remote copy with RSync, remote viewing with TigerVNC.
- Key management with Pass and KeePass, file encryption with eCryptFS and GPG.
Personal files
I have one repository used to configure and administrate my computer. Find a way to get the SSH key located in my dotfiles (SSH-based copy using password authentication, USB key transfer, Syncthing synchronization). For instance, using SSH on a machine which have the key:
ip=192.168.1.1 ssh-copy-id drac@$ip ssh drac@$ip "echo '$(cat ~/.ssh/id_rsa.pub)' > ~/.ssh/id_rsa.pub" ssh drac@$ip "echo '$(cat ~/.ssh/id_rsa)' > ~/.ssh/id_rsa" ssh drac@$ip "chmod 600 ~/.ssh/id_rsa"
Then, clone and follow the README:
git clone git@github.com:pierreay/bootstrap.git
Footnotes
UKI signing
Check what specific files need to be signed for secure boot to work:
sbctl verify
The UKI (/efi/EFI/Linux/arch-linux.efi) should be detected as an unsigned file. Let's sign it and register the signature inside the sbctl database:
sbctl sign --save /efi/EFI/Linux/arch-linux.efi
Our UKI is now signed and Secure Boot is ready to work. Reboot into the firmware settings, enable Secure Boot, and reboot again to check it works the intended way and display the status:
sbctl status
sbctl comes with a [Pacman hook](arch_linux.html) that automatically signs all new files that are registered into its database whenever the kernel or systemd is updated.
TPM2 enrolling
We can now enroll the TPM in order to use it unlock the LUKS volume. To do so, we will use the [SystemD](unix.html) cryptenroll command. First, automatically generate a recovery key that can be used in case of a problem with the TPM:
systemd-cryptenroll /dev/sda2 --recovery-key
Store this recovery key in another location than the LUKS container (e.g., USB key or a trusted computer).
Second, remove the passphrase created during the LUKS format process and create a key bound to the TPM PCR 7 (Secure Boot state and firmware certificates (PK, KEK, etc.)):
systemd-cryptenroll /dev/sda2 --wipe-slot=empty --tpm2-device=auto
As of now, the TPM will automatically release the key as long as the boot chain is not tampered.
To make the UKI grab the key in order for the [initramfs](linux_kernel.html) to unlock the LUKS container, we need to embed the tpm2-device=auto LUKS option in the kernel command-line parameter inside the UKI. To do so, referring to the UKI creation section above, add the LUKS option in a new rd.luks.options kernel parameter:
rd.luks.options=DEVUUID=tpm2-device=auto
Don't forget to regenerate and resign the UKI after this step – or simply, regenerating the initramfs will execute the Pacman hooks performing those two tasks.
UEFI protection
Since the TPM will automatically provides the LUKS key for decryption if the UEFI configuration integrity is validated, it is necessary to protect the UEFI firmware with a strong password. You can use the same password for:
- Prevents an attacker to disable Secure Boot by entering the UEFI setup. If this happens despite the protection, the attacker could not boot the encrypted drive since the TPM would not release the key, but still use the laptop to boot another OS. Enable Boot Device List protection by password as well.
- Requests the physical presence of the user at boot time.
Kernel protection
Using all of those security systems against attacker from boot-time, one may surely want to protect also from run-time by enabling [kernel lockdown](optimization.html).