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.
Thank you very much, this is the setup I've been looking to use while I learn more and it worked like a charm.
Quick question. There's no microcode entry in hooks of step 27. Is this intentional? Don't know enough yet to say either way but thought this might need to be included, as the pacman trigger to rebuild involves the microcode. I included it in mine and it worked but will redo and remove if it's not necessary. EDIT: NVM, further reading tells me it's not needed.