Update 2026: added btrfs with transparent ZSTD encryption to save SSD space.
My old install process is here. In this one, I switched to UKIs (Unified Kernel Images) and systemd-boot, for a faster, cleaner setup. This is a clean way to have peaceful coexistence with other OSes on the same drive. And it paves the way for secure boot in case you need to have a virus OS like Windows installed.
Table of Contents
Boot into Arch Installation Image
See the official guide.
Format Drive
-
cfdisk /dev/nvme0n1- choose GPT partition table
- make a 5G partition for the EFI System Partition. 5G is excessive but leaves room to expand and add more OSes. Toggle it bootable, and change its type to
EFI System - ESP filesystem must be FAT32:
mkfs.fat -F32 /dev/nvme0n1p1 - make the remaining free space into Linux filesystem partitions, one for each root.
In this example, I'm putting my first OS, the encrypted one, on /dev/nvme0n1p2, and the second one on /dev/nvme0n1p3
Install Main OS
This is encrypted Arch on /dev/nvme0n1p2.
Encrypt root partition
cryptsetup -v luksFormat /dev/nvme0n1p2- open the partition:
cryptsetup open /dev/nvme0n1p2 crypt
Prepare Arch partition
mkfs.btrfs /dev/mapper/cryptmount -o noatime,compress=zstd /dev/mapper/crypt /mnt/
Mount ESP
mkdir /mnt/efimount /dev/nvme0n1p1 /mnt/efi
Install system
pacstrap /mnt base base-devel linux mkinitcpio linux-firmware intel-ucode networkmanager gnome emacs git vim ripgrep just aspell-en words direnv syncthing firefox gdm stow keepassxc bluez rustup tree-sitter-rust bluez-utils cmake chromium ttf-iosevka-nerd gnome-tweaks bash-completion usbutils sof-firmware okular notmuch isync rsync gdb zig zls zstd restic dosfstools inetutils whisper-cpp wl-clipboard btrfs-progs seahorse signal-desktop podman
Chroot in and configure system time, language, etc
arch-chroot /mnt/echo "my_hostname" > /etc/hostnameln -sf /usr/share/zoneinfo/America/New_York /etc/localtime- uncomment language in
/etc/locale.gen -
edit
/etc/vconsole.confand put the keyboard language (e.g.LANG=en_US.UTF-8)- Required by the
sd-vconsolemkinitcpio hook, you can't leave it blank
- Required by the
locale-genlocale > /etc/locale.conf
Set up Kernel and Bootloader
-
edit the HOOKS array in
/etc/mkinitcpio.confand:- add
sd-encryptafterblock - (Source for kernel hooks)
- add
Edit kernel command flags by adding them (optionally separated by newlines to /etc/kernel/cmdline:
root=/dev/mapper/crypt
rd.luks.name=<UUID of /dev/nvme0n1p2>=crypt
rootflags=compress=zstd:3
rw(Source for kernel arguments)
Enable UKIs by changing the mkinitcpio preset at /etc/mkinitcpio.d/linux.preset:
ALL_config="/etc/mkinitcpio.conf"
ALL_kver="/boot/vmlinuz-linux"
PRESETS=('default')
default_uki="/efi/EFI/Linux/arch-linux.efi"
default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"(Source for mkinitcpio configuration)
Create the directories /efi/EFI/Linux. This is where systemd-boot automatically looks for kernel images.
Generate the ramdisk: mkinitcpio -p linux
Install Bootloader
bootctl install
User and root setup
- set root passwd:
passwd useradd -m -g wheel -s /bin/bash youruserpasswd youruservisudosystemctl enable NetworkManager.servicesystemctl enable gdm.servicesystemctl enable bluetooth.service- Now make sure you can boot into the system before continuing with final configurations
Final configurations after rebooting
- Enable autologin since there's no reason to authenticate after you typed in the encryption passphrase
-
MAC address spoofing:
- to turn it on by default, edit
/etc/NetworkManager/NetworkManager.confand add:
- to turn it on by default, edit
[connection]
wifi.cloned-mac-address=random
[connection]
ethernet.cloned-mac-address=random- Now every new connection (including new connections to the same network) will have a random MAC address
-
Firewall:
sudo pacman -S ufwsudo systemctl enable ufw.servicesudo ufw default deny
Swap and hibernate
Sources
- https://wiki.archlinux.org/title/Btrfs#Swap_file
- https://wiki.archlinux.org/title/Power_management/Suspend_and_hibernate#Pass_hibernate_location_to_initramfs
- https://wiki.archlinux.org/title/Dm-crypt/Swap_encryption#With_suspend-to-disk_support
btrfs subvolume create /swapbtrfs filesystem mkswapfile --size 8g --uuid clear /swap/swapfileswapon /swap/swapfileecho "/swap/swapfile none swap defaults 0 0" >> /etc/fstab- vim
/etc/systemd/logind.confand add:HandleLidSwitch=suspend-then-hibernate- - edit
/etc/systemd/sleep.confand add:HibernateDelaySec=10800 # 3hrs - amazingly, on a uefi system, this is now all that's needed for working hibernation, and closing the lid will suspend quickly, but go to full hibernation after 3 hours (or at 5% battery, whichever comes first).
Adding a second OS
The steps are identical for adding the second OS, except you're installing to a different partition. That means you need to:
- change
rootandresumekernel arguments - change the name of the UKI in
/etc/mkinitcpio.d/linux.preset
Furthermore, you can skip installing systemd-boot a second time. The existing bootloader will automatically pick up your new UKI in EFI/Linux/ on the ESP.
Using systemd-boot
By default, systemd-boot has a timeout of 0 so it will immediately boot the default OS without giving a choice. You can set the timeout option in /efi/loader/loader.conf if you want to always see the menu. See the man page for some more options to set.
However, I prefer to leave the timeout at 0 for the fastest possible boot. The trick is you can press and hold Spacebar once the OEM splash screen displays (e.g. the Lenovo logo). This will show the systemd-boot menu for this boot only. You can then choose a default OS by scrolling to it in the menu and pressing 'd'.
Notes
/swapfilesize: It needs to be big enough to cover the memory image, but modern kernels compress the image a lot. You can actually view/sys/power/image_sizeto see the size after compression. Also, the swapfile can easily be resized at any time. So my advice is to use 16GB or 1/2 of your RAM, whichever is larger, and if it's not enough you can always grow it later.- If the second installation is unencrypted, you can simply skip the
rootkernel command line argument andsystemd-auto-gpt-generatorwill guess the partition for you (source).
See Also
- https://man.archlinux.org/man/loader.conf.5#OPTIONS
- https://wiki.archlinux.org/title/Systemd-boot
- https://wiki.archlinux.org/title/Mkinitcpio
- https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system
- https://wiki.archlinux.org/title/Kernel_parameters#Parameter_list
- https://wiki.archlinux.org/title/Unified_kernel_image
- https://wiki.archlinux.org/title/EFI_system_partition