Boot from an Arch Linux live USB.
Set the keyboard layout to your language, here I am using the French keyboard layout:
Set the clock to your timezone:
timedatectl set-timezone Europe/Paris timedatectl set-ntp true
List the disks:
Choose the desired disk and create 3 (or 4) partitions:
- An EFI partition (for UEFI)
- A boot partition (for the bootloader)
- A root partition ( / )
- Optionally, a home partition ( /home )
Partition the disk using
The EFI partition should be 500MiB.
mklabel gpt mkpart primary fat32 1MiB 501MiB # EFI partition set 1 esp on mkpart primary ext4 501MiB 20.5GiB # Root partition, approximately 20GiB mkpart primary ext4 20.5GiB 100% # Home partition, using the remaining space q
mklabel gpt mkpart primary fat32 1MiB 551MiB # EFI partition set 1 esp on mkpart primary ext4 551MiB 100% # Root partition q
Encryption of Partitions
Choose a passphrase (long enough) for the
/root partition (and one for the
/home partition if you have one) and encrypt the partition(s). We will use AES with a 512-bit key, a key derivation time of 5000 ms, and the Argon2id algorithm.
cryptsetup -v --type luks -c aes-xts-plain64 -s 512 -h sha512 --pbkdf argon2id -i 5000 -y luksFormat /dev/sdX2 cryptsetup -v --type luks -c aes-xts-plain64 -s 512 -h sha512 --pbkdf argon2id -i 5000 -y luksFormat /dev/sdX3
Mount the partition(s):
cryptsetup open /dev/sdX2 root cryptsetup open /dev/sdX3 home
Format the partitions as ext4 (except for the EFI partition, which is formatted as fat32):
mkfs.fat -F32 /dev/sdX1 mkfs.ext4 /dev/mapper/root mkfs.ext4 /dev/mapper/home
Arch Linux Installation
Mount the various partitions under
mount /dev/mapper/root /mnt mkdir /mnt/home && mount /dev/mapper/home /mnt/home # If using /home partition mkdir -p /mnt/boot/efi && mount /dev/sda1 /mnt/boot/efi
Install the base packages and the hardened kernel (replace
linux for the regular kernel):
pacstrap /mnt base base-devel linux-hardened linux-hardened-headers linux-firmware
genfstab -U /mnt >> /mnt/etc/fstab
Arch Linux Configuration
chroot command to enter our new installation as the root:
Choose the hostname for the machine (here we use MachineName as an example):
echo MachineName > /etc/hostname echo '127.0.0.1 MachineName.localdomain MachineName' >> /etc/hosts
Configure the clock:
ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime hwclock --systohc
Generate the system’s locales:
sed -i 's/#fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/' /etc/locale.gen locale-gen echo LANG="fr_FR.UTF-8" > /etc/locale.conf export LANG=fr_FR.UTF-8
sed -i 's/#en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen locale-gen echo LANG="en_US.UTF-8" > /etc/locale.conf export LANG=en_US.UTF-8
Configure the keyboard layout as AZERTY:
echo KEYMAP=fr > /etc/vconsole.conf
Set a password for the
Boot and Decryption Management
efibootmgr and a text editor:
pacman -S efibootmgr <TEXT_EDITOR>
Since we haven’t created a separate partition for
/boot, we will create a unified kernel image so that our installation can be bootable.
Brief explanation of the Linux boot process
Typically, to boot a Linux system, the UEFI (the motherboard firmware) starts by loading a bootloader, a program that “prepares” the system to boot the Linux kernel. The bootloader is a .efi file located on the first partition of the disk. It loads a CPU microcode (a set of patches provided by the CPU manufacturer to ensure its stability), an initramfs (which creates an initial file system to access the root file system), and finally a Linux kernel. It also allows passing parameters to the kernel before booting. For more information, see https://wiki.archlinux.org/title/Arch_boot_process.
Some bootloaders, such as GRUB or systemd-boot, allow choosing between multiple kernels or operating systems (in the case of multiboot).
In our case, we will configure the system to boot directly into the kernel without using a bootloader (reducing the attack surface) by compiling the CPU microcode, initramfs, the kernel, and its arguments into a single .efi file that can be launched directly by the motherboard.
Install the microcode for Intel and AMD processors:
pacman -S amd-ucode # for AMD pacman -S intel-ucode # for Intel
If you are installing Arch on a bootable USB drive, you can install the microcodes for Intel and AMD to support different processors.
Kernel Boot Arguments
Retrieve the UUID of the
lsblk -f /dev/sdX2
- Add the options
- Add the disk decryption information
cryptdevice=UUID=<partition UUID>:root root=/dev/mapper/root(the UUID is the one where FSTYPE is
lsblk -f /dev/sdXcommand)
- Finally, add the options
loglevel=3 quiet bgrt_disable
Your file should look like this:
pti=on page_alloc.shuffle=1 rw cryptdevice=UUID=XXXXXXXX-XXXX-4XXX-XXXX-XXXXXXXXXXXX:root root=/dev/mapper/root mem_sleep_default=deep loglevel=3 quiet bgrt_disable
If you are using an SSD, which is likely, you can improve performance for dm-crypt in terms of reading and writing by disabling asynchronous reads and writes and queuing mechanisms: replace the
cryptdevice=UUID=<partition UUID>:root root=/dev/mapper/root part with
cryptdevice=UUID=<YOUR UUID>:root:no-read-workqueue,no-write-workqueue root=/dev/mapper/root
Generating EFI Images
/etc/mkinitcpio.conf file and add the
encrypt hooks, which will allow us to decrypt our root partition during boot:
HOOKS=(base udev autodetect modconf block filesystems keyboard fsck keymap encrypt)
If you have a partition for
/home, modify the
/etc/fstab file to avoid using the
/dev/mapper/home for mounting. Comment out the corresponding line and add one last line containing:
/dev/mapper/home /home ext4 rw,relatime,data=ordered 0 2
If you have an SSD and want to improve its longevity, you can replace
/etc/fstab. This will disable file access timestamp updates and reduce the number of disk writes.
Now we will create an mkinitcpio preset to generate a bootable unified image. Edit the
/etc/mkinitcpio.d/linux-hardened.preset file and add the following content:
# mkinitcpio preset file for the 'linux-hardened' unified image ALL_config="/etc/mkinitcpio.conf" ALL_kver="/boot/vmlinuz-linux-hardened" ALL_microcode="/boot/*-ucode.img" PRESETS=('default' 'fallback') default_image="/boot/initramfs-linux-hardened.img" default_uki="/boot/efi/EFI/Linux/archlinux-linux.efi" default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp" fallback_image="/boot/initramfs-linux-hardened-fallback.img" fallback_options="-S autodetect" fallback_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp" fallback_uki="/boot/efi/EFI/Linux/archlinux-linux-fallback.efi"
This preset will allow us to generate two EFI files:
/boot/efi/EFI/Linux/archlinux-linux-fallback.efi, containing our CPU microcode, initramfs, and kernel.
Generate the EFI images:
mkdir -p /boot/efi/EFI/Linux mkinitcpio -p linux-hardened
Adding UEFI Entries
Add the UEFI entries for our images so that we can select them in our motherboard:
efibootmgr --create --disk /dev/sdX --part 1 --label "Arch Linux" --loader 'EFI\Linux\archlinux-linux.efi' --unicode efibootmgr --create --disk /dev/sdX --part 1 --label "Arch Linux Fallback" --loader 'EFI\Linux\archlinux-linux-fallback.efi' --unicode
At this point, your system should be bootable.
Setting Up Secure Boot
Now that our system can boot, we will set up secure boot.
Secure Boot is a security mechanism that verifies the integrity of the kernel and modules loaded during boot. It ensures that the loaded files are signed with a cryptographic key, thereby ensuring they haven’t been tampered with by an attacker.
The first step to setting up secure boot is to install a tool for managing signatures and keys. We will install
pacman -S sbctl
Next, we will generate keys that will be used to sign our efi files:
Then, we will enroll our keys in the motherboard:
You may need to restart your system and enter the UEFI to enter setup or audit mode (depending on how your motherboard manufacturer calls it) to have the opportunity to enroll the keys.
If enrolling the keys fails, you can try using
sbctl enroll-keys --microsoftto enroll the Microsoft keys in addition to the ones you have generated. Some devices have their firmware signed with Microsoft keys, and your computer might refuse to boot without them…
Now, we will sign our efi files:
sbctl sign -s /boot/efi/EFI/Linux/archlinux-linux.efi sbctl sign -s /boot/efi/EFI/Linux/archlinux-linux-fallback.efi
We can now verify that the files are properly signed:
Finally, reboot, enable secure boot in the UEFI, and verify that the system boots correctly.
To ensure that everything is properly configured, you can use
sbctl status to check if secure boot is enabled and the keys are enrolled.
sbctl sign-allcommand can be used to sign all previously signed efi files. If you have modified any of the efi files, for example with
mkinitcpio, you can use this command to sign them again.
Disk Decryption via SSH
If you want to be able to use your computer remotely (e.g., by turning it on via Wake-on-LAN), you will need to decrypt the disks before even launching the kernel. For this, we can use Dropbear, an SSH client that starts with the bootloader.
pacman -S mkinitcpio-dropbear mkinitcpio-utils mkinitcpio-netconf
Generate an Ed25519 key pair that will be used for SSH login:
ssh-keygen -t ed25519 -f ~/.ssh/dropbear_ssh
Copy the public key to the Dropbear configuration folder:
cp ~/.ssh/dropbear_ssh.pub /etc/dropbear/root_key
Copy the private key to the device you will use to decrypt your disk.
encryptssh hooks to the `/etc/mk
HOOKS=(base udev autodetect modconf block netconf dropbear keyboard keymap encryptssh filesystems fsck)
/etc/kernel/cmdline file and add an
ip field has the following format:
For example, to have your computer start with the IP address
192.168.1.22 on the
192.168.1.0/24 network with a gateway at
To automatically detect the network configuration and use DHCP:
Generating EFI Images
Regenerate the EFI files:
mkinitcpio -p linux-hardened
On the next boot, you will have the option to connect to your computer via SSH using the generated key. You only need to enter the decryption key for your disk, and your computer will boot.
Installing Base Packages and Tweaks
If you want to install additional packages on your installation, you will need internet access. Before exiting the installation media, install
pacman -S networkmanager systemctl enable NetworkManager
If you want additional protection against memory-related security vulnerabilities (such as buffer overflow), you can replace the glibc malloc implementation with the one provided by the GrapheneOS team: hardened_malloc.
Hardened Malloc is not available in the official Arch Linux repositories but can be found in the community repositories (https://aur.archlinux.org/packages/hardened_malloc). Unfortunately, at the time of writing this tutorial, the maintainer’s signature is no longer valid. Therefore, we will install it manually.
Clone the repository and compile the library:
git clone https://github.com/GrapheneOS/hardened_malloc/ cd hardened_malloc git checkout tags/11 # use the latest version (in this case, version 11) make # compile hardened_malloc
To ensure there are no issues, increase the number of usable memory maps on the system:
echo 'vm.max_map_count = 1048576' > /etc/sysctl.d/hardened_malloc.conf
Install the library on the system:
cp out/libhardened_malloc.so /usr/local/lib/libhardened_malloc.so
Ensure that hardened_malloc is loaded for each program:
echo '/usr/local/lib/libhardened_malloc.so' >> /etc/ld.so.preload
Congratulations! You have installed hardened_malloc on your system. To verify, you can run a program and check if
libhardened_malloc.so is being loaded:
cat /proc/<PID>/maps | grep hardened_malloc