Arch Linux Install with BTRFS, LUKS, and systemd-boot, dual-booted with a UKI and Windows 11 on a shared EFI partition
Last updated 2025-09-28
Disclaimer: I have personally tested the steps in this install. However, I'm not responsible for anything you do.
- Boot Windows, install the latest updates, remove OEM bloatware, open Disk Management, and shrink the Windows partition to make room for Arch.
- Download the latest Arch ISO and flash it with Etcher.
Control Panel > Power Options > Choose what the power buttons do > Change settings that are currently unavailable> UncheckFast startup.regedit > HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation> Create a newDWORD, name itRealTimeIsUniversal, and set it to1.- Boot gparted-live, move the last two tiny Windows partitions to the left.
- Turn off secure boot in BIOS, reboot into the Arch ISO.
Note: the following steps (until the first reboot) should be done all in one go without unnecessary reboots (including back to Windows).
- Turn down brightness:
echo 20 > /sys/class/backlight/<screen>/brightness - Connect to Ethernet/WiFi:
iwctl>station list>station <device> scan>station <device> get-networks>station <device> connect <SSID>> Ctrl+d >ping 1.1.1.1
- If you get an error, you might need to
rfkill unblock wlanand/orip link set <device> up
cat /sys/firmware/efi/fw_platform_size> check that your computer is 64-bit. If it's not, this guide is not for you, you should try another guide (make sure to re-enable secure boot before booting back into Windows).timedatectl> check that NTP is active, and that RTC is not in local TZ. If either are not, runtimedatectl set-ntp true && timedatectl set-local-rtc truefdisk -lto check your disks' and partitions' current configurations.cfdisk /dev/nvme0n1(or/dev/sda1if using SATA rather than NVME disks) > Scroll down using arrow keys toFree Space>[New]to create a newLinux Filesystempartition > Choose your size and PressEnter. Write and quit.- Setup and open LUKS (replace
Xwith the partition number of the partition you just created (e.g. 6):cryptsetup luksFormat /dev/nvme0n1pX cryptsetup open /dev/nvme0n1pX luks - Create and mount BTRFS:
mkfs.btrfs -L arch /dev/mapper/luks mount /dev/mapper/luks /mnt - Create BTRFS subvolumes:
btrfs subvolume create /mnt/@ btrfs subvolume create /mnt/@swap btrfs subvolume create /mnt/@home btrfs subvolume create /mnt/@log btrfs subvolume create /mnt/@cache btrfs subvolume create /mnt/@scratch - Remount:
umount /mnt mount -o noatime,ssd,compress=zstd,subvol=@ /dev/mapper/luks /mnt - Create mountpoints:
mkdir -p /mnt/{boot,home,var/log,var/cache,scratch,btrfs} - Mount subvols:
mount -o noatime,ssd,compress=zstd,subvol=@home /dev/mapper/luks /mnt/home mount -o noatime,ssd,compress=zstd,subvol=@log /dev/mapper/luks /mnt/var/log mount -o noatime,ssd,compress=zstd,subvol=@cache /dev/mapper/luks /mnt/var/cache mount -o noatime,ssd,compress=zstd,subvol=@scratch /dev/mapper/luks /mnt/scratch mount -o noatime,ssd,compress=zstd,subvolid=5 /dev/mapper/luks /mnt/btrfs # const 5 for BTRFS's root - Mount EFI partition:
mount /dev/nvme0n1p1 /mnt/boot - Create swapfile:
cd /mnt/btrfs/@swap btrfs filesystem mkswapfile --size 20g --uuid clear ./swapfile # replace 20 with a number slightly larger than your ram if you want to hibernate swapon ./swapfile cd - Configure mirrorlist:
cp /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.bak # backup mirrorlist reflector -c "CA" -f 12 -l 10 -n 12 --save /etc/pacman.d/mirrorlist # (replace CA with your country code) pacman -Syy
- Uncomment following lines for 32-bit pkgs:
vim /etc/pacman.conf --- [multilib] Include = /etc/pacman.d/mirrorlist
- Install base system:
- AMD:
pacstrap -K /mnt base base-devel linux-lts linux-firmware btrfs-progs \ amd-ucode mesa xf86-video-amdgpu vulkan-radeon libva-mesa-driver mesa-vdpau \ networkmanager sudo neovim git reflector - Intel:
pacstrap -K /mnt base base-devel linux-lts linux-firmware btrfs-progs \ intel-ucode mesa xf86-video-intel vulkan-intel intel-media-driver \ networkmanager sudo neovim git reflector
- Init
fstaband verify after:genfstab -U /mnt >> /mnt/etc/fstab - Chroot into the new system:
arch-chroot /mnt - Set timezone:
ln -sf /usr/share/zoneinfo/America/Toronto /etc/localtime # replace with your timezone hwclock --systohc --utc - Set locale: uncomment desired locales from
/etc/locale.gen:locale-gen echo "LANG=en_CA.UTF-8" > /etc/locale.conf export LANG=en_CA.UTF-8 - Set hostname:
echo "arch" > /etc/hostname # replace with your hostname - Add hosts (replace hostname with your hostname):
alias vim=nvim vim /etc/hosts --- 127.0.0.1 <hostname>.localdomain localhost ::1 localhost.localdomain localhost - Set root password:
passwd - Create your user:
useradd -mG wheel,storage,power,log,adm,uucp,tss,rfkill -s /bin/bash <username> # replace with your username passwd <username> - Give user sudo access:
EDITOR=nvim visudo --- # raymo ALL=(ALL:ALL) ALL # for passworded sudo # raymo ALL=(ALL:ALL) NOPASSWD:ALL # for passwordless sudo # only uncomment (remove the leading #) one of the two above, replace raymo with your username - Enable NetworkManager:
systemctl enable NetworkManager mkinitcpio:vim /etc/mkinitcpio.conf --- HOOKS=(base keyboard systemd autodetect modconf kms block keymap sd-vconsole sd-encrypt btrfs filesystems fsck)- Configure kernel parameters:
vim /etc/kernel/cmdline --- root=/dev/mapper/luks rootflags=subvol=@,x-system.device-timeout=30 rw quiet splash bgrt_disable resume=/dev/mapper/luks resume_offset=<offset>
- Get offset from:
btrfs inspect-internal map-swapfile -r /btrfs/@swap/swapfile
- Create crypttab:
vim /etc/crypttab.initramfs --- luks UUID=<uuid> - discard,tpm2-device=auto
- Get UUID from:
blkid /dev/nvme0n1pX
- Configure
.preset:vim /etc/mkinitcpio.d/linux-lts.preset
- Uncomment the
default_uki=lines, replace any/efi/*with/boot/*, comment out thedefault_image=line, uncomment splash if desired, comment out fallback lines, remove'fallback'from thePRESETSline - Make sure
/boot/EFI/Linuxexists (whereukipoints to). If it doesn't,mkdir -p /boot/EFI/Linux.
- Install
systemd-boot:chmod 700 /boot bootctl --path=/boot install chmod 700 /boot/loader/random-seed mkinitcpio -P- Install userspace apps:
pacman -S plasma kde-applications - Enable
sddm:systemctl enable sddm - Configure
make:vim /etc/makepkg.conf --- MAKEFLAGS="-j$(nproc --ignore=2)" # 2 less than total threads - Install
yay:sudo -su <username> git clone https://aur.archlinux.org/yay.git cd yay makepkg -si exit - Exit chroot, unmount, shutdown:
exit umount -R /mnt shutdown now
- If you get the
target is busyerror duringumount, check what's going on with:fuser -m /mnt
- Configure BIOS boot order. Set Linux as first boot option because
systemd-bootwill auto-detect Windows and add it to the boot menu. - Boot into Arch and pat yourself on the back.
- Enroll TPM so you don't have to keep typing in your LUKS password:
sudo systemd-cryptenroll --tpm2-device=<path> --tpm2-pcrs=7 /dev/nvme0n1pX
- Get path from:
sudo systemd-cryptenroll --tpm2-device=list
- Install UKI pacman hook to trigger rebuild after ucode update:
sudo mkdir -p /etc/pacman.d/hooks/ sudo nvim /etc/pacman.d/hooks/ucode.hook --- [Trigger] Operation=Install Operation=Upgrade Operation=Remove Type=Package # Change to appropriate microcode package Target=amd-ucode # Change the linux part above and in the Exec line if a different kernel is used Target=linux [Action] Description=Update Microcode module in initcpio Depends=mkinitcpio When=PostTransaction NeedsTargets Exec=/bin/sh -c 'while read -r trg; do case $trg in linux) exit 0; esac; done; /usr/bin/mkinitcpio -P' - Install
sbctlandefitools:yay -S sbctl efitools - Backup your existing keys:
for var in PK KEK db dbx ; do efi-readvar -v $var -o old_${var}.esl ; done - Reboot into bios and delete the manufacturer PK/all keys. Reboot back into Arch.
- Setup sbctl:
sudo sbctl status sudo sbctl create-keys sudo chattr -i /sys/firmware/efi/efivars/{PK,KEK,db}* sudo sbctl enroll-keys -m sudo sbctl verify # shows you what to sign # e.g. # sudo sbctl sign -s /boot/EFI/Boot/bootx64.efi # sudo sbctl sign -s /boot/EFI/Linux/arch-linux-lts.efi # sudo sbctl sign -s /boot/EFI/systemd/systemd-bootx64.efi - Add a hook for automatically signing after upgrades:
sudo vim /etc/initcpio/post/uki-sbctl --- #!/usr/bin/env bash sbctl sign-all --- sudo chmod +x /etc/initcpio/post/uki-sbctl - Setup
snapper - Shutdown, set an admin bios password if you haven't already, and reboot.
- Turn off secure boot
- Boot into an Arch liveUSB
- Unlock luks:
cryptsetup open /dev/nvme0n1pX luks - Mount the unlocked partition:
mount -o noatime,ssd,compress=zstd,subvol=@ /dev/mapper/luks /mnt - Mount the EFI partition:
mount /dev/nvme0n1p1 /mnt/boot - Chroot into the FS:
arch-chroot /mnt - Fix your EFI partition:
mkinitcpio -P - Turn secure boot back on.
Updated, thanks.