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-05-05
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 wlan
and/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 true
fdisk -l
to check your disks' and partitions' current configurations.cfdisk /dev/nvme0n1
(or/dev/sda1
if using SATA rather than NVME disks) > Scroll down using arrow keys toFree Space
>[New]
to create a newLinux Filesystem
partition > Choose your size and PressEnter
. Write and quit.- Setup and open LUKS (replace
X
with 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
fstab
and 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 command line:
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 thePRESETS
line - Make sure
/boot/EFI/Linux
exists (whereuki
points 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 busy
error duringumount
, check what's going on with:fuser -m /mnt
- Configure BIOS boot order. Set Linux as first boot option because
systemd-boot
will 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
sbctl
andefitools
: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, enable secureboot and delete the manufacturer PK. 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 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 for script. I'm going to try it on my desktop. Two questions.