Skip to content

Instantly share code, notes, and snippets.

@Raymo111
Last active May 11, 2025 00:10
Show Gist options
  • Save Raymo111/5771e425d6e0b9b095660696b92e1a3e to your computer and use it in GitHub Desktop.
Save Raymo111/5771e425d6e0b9b095660696b92e1a3e to your computer and use it in GitHub Desktop.
Arch Linux Install with BTRFS, LUKS, and systemd-boot, dual-booted with a UKI and Windows 11 on a shared EFI partition

Arch Linux Install with BTRFS, LUKS, and systemd-boot, dual-booted with a UKI and Windows 11 on a shared EFI partition

By Raymo111

Last updated 2025-05-05

Disclaimer: I have personally tested the steps in this install. However, I'm not responsible for anything you do.

Pre-install

  1. Boot Windows, install the latest updates, remove OEM bloatware, open Disk Management, and shrink the Windows partition to make room for Arch.
  2. Download the latest Arch ISO and flash it with Etcher.
  3. Control Panel > Power Options > Choose what the power buttons do > Change settings that are currently unavailable > Uncheck Fast startup.
  4. regedit > HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation > Create a new DWORD, name it RealTimeIsUniversal, and set it to 1.
  5. Boot gparted-live, move the last two tiny Windows partitions to the left.
  6. 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).

Install

  1. Turn down brightness:
    echo 20 > /sys/class/backlight/<screen>/brightness
    
  2. 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/or ip link set <device> up
  1. 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).
  2. timedatectl > check that NTP is active, and that RTC is not in local TZ. If either are not, run timedatectl set-ntp true && timedatectl set-local-rtc true
  3. fdisk -l to check your disks' and partitions' current configurations.
  4. cfdisk /dev/nvme0n1 (or /dev/sda1 if using SATA rather than NVME disks) > Scroll down using arrow keys to Free Space > [New] to create a new Linux Filesystem partition > Choose your size and Press Enter. Write and quit.
  5. 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
    
  6. Create and mount BTRFS:
    mkfs.btrfs -L arch /dev/mapper/luks
    mount /dev/mapper/luks /mnt
    
  7. 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
    
  8. Remount:
    umount /mnt
    mount -o noatime,ssd,compress=zstd,subvol=@ /dev/mapper/luks /mnt
    
  9. Create mountpoints:
    mkdir -p /mnt/{boot,home,var/log,var/cache,scratch,btrfs}
    
  10. 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
    
  11. Mount EFI partition:
    mount /dev/nvme0n1p1 /mnt/boot
    
  12. 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
    
  13. 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
    
  1. 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
    
  1. Init fstab and verify after:
    genfstab -U /mnt >> /mnt/etc/fstab
    
  2. Chroot into the new system:
    arch-chroot /mnt
    
  3. Set timezone:
    ln -sf /usr/share/zoneinfo/America/Toronto /etc/localtime # replace with your timezone
    hwclock --systohc --utc
    
  4. 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
    
  5. Set hostname:
    echo "arch" > /etc/hostname # replace with your hostname
    
  6. Add hosts (replace hostname with your hostname):
    alias vim=nvim
    vim /etc/hosts
    ---
    127.0.0.1 <hostname>.localdomain localhost
    ::1 localhost.localdomain localhost
    
  7. Set root password:
    passwd
    
  8. Create your user:
    useradd -mG wheel,storage,power,log,adm,uucp,tss,rfkill -s /bin/bash <username> # replace with your username
    passwd <username>
    
  9. 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
    
  10. Enable NetworkManager:
    systemctl enable NetworkManager
    
  11. mkinitcpio:
    vim /etc/mkinitcpio.conf
    ---
    HOOKS=(base keyboard systemd autodetect modconf kms block keymap sd-vconsole sd-encrypt btrfs filesystems fsck)
    
  12. 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
    
  1. Create crypttab:
    vim /etc/crypttab.initramfs
    ---
    luks           UUID=<uuid>    -                       discard,tpm2-device=auto
    
  • Get UUID from:
     blkid /dev/nvme0n1pX
    
  1. Configure .preset:
    vim /etc/mkinitcpio.d/linux-lts.preset
    
  • Uncomment the default_uki= lines, replace any /efi/* with /boot/*, comment out the default_image= line, uncomment splash if desired, comment out fallback lines, remove 'fallback' from the PRESETS line
  • Make sure /boot/EFI/Linux exists (where uki points to). If it doesn't, mkdir -p /boot/EFI/Linux.
  1. Install systemd-boot:
    chmod 700 /boot
    bootctl --path=/boot install
    chmod 700 /boot/loader/random-seed
    
  2. mkinitcpio -P
  3. Install userspace apps:
    pacman -S plasma kde-applications
    
  4. Enable sddm:
    systemctl enable sddm
    
  5. Configure make:
    vim /etc/makepkg.conf
    ---
    MAKEFLAGS="-j$(nproc --ignore=2)" # 2 less than total threads
    
  6. Install yay:
    sudo -su <username>
    git clone https://aur.archlinux.org/yay.git
    cd yay
    makepkg -si
    exit
    
  7. Exit chroot, unmount, shutdown:
    exit
    umount -R /mnt
    shutdown now
    
  • If you get the target is busy error during umount, check what's going on with:
     fuser -m /mnt
    
  1. Configure BIOS boot order. Set Linux as first boot option because systemd-boot will auto-detect Windows and add it to the boot menu.
  2. Boot into Arch and pat yourself on the back.
  3. 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
    
  1. 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'
    
  2. Install sbctl and efitools:
    yay -S sbctl efitools
    
  3. Backup your existing keys:
    for var in PK KEK db dbx ; do efi-readvar -v $var -o old_${var}.esl ; done
    
  4. Reboot into bios, enable secureboot and delete the manufacturer PK. Reboot back into Arch.
  5. 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
    
  6. 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
    
  7. Setup snapper
  8. Shutdown, set an admin bios password if you haven't already, and reboot.

How to fix Arch when Windows update kills your EFI partition

  1. Turn off secure boot
  2. Boot into an Arch liveUSB
  3. Unlock luks:
    cryptsetup open /dev/nvme0n1pX luks
    
  4. Mount the unlocked partition:
    mount -o noatime,ssd,compress=zstd,subvol=@ /dev/mapper/luks /mnt
    
  5. Mount the EFI partition:
    mount /dev/nvme0n1p1 /mnt/boot
    
  6. Chroot into the FS:
    arch-chroot /mnt
    
  7. Fix your EFI partition:
    mkinitcpio -P
    
  8. Turn secure boot back on.
@marol75
Copy link

marol75 commented Dec 24, 2023

Thank you for script. I'm going to try it on my desktop. Two questions.

  1. Once (~a year ago) I tried to make swap-file, but it didn't work. I've read it's not supported by archlinux. Will it be ok to make swap partition (and encrypt it)?
  2. Step 45 - secure boot has already been enabled at step 42 or it's a mistake?

@marol75
Copy link

marol75 commented Jan 1, 2024

I've got another question.
After step 27 there's no mkinitcpio command. Why?

@Raymo111
Copy link
Author

Raymo111 commented Apr 6, 2024

I've got another question. After step 27 there's no mkinitcpio command. Why?

Updated, thanks.

@SHADOW-REX
Copy link

I have a question, you included the luks line in crypttab but not in crypttab.initramfs, why?

@Raymo111
Copy link
Author

I have a question, you included the luks line in crypttab but not in crypttab.initramfs, why?

I don't give any instructions for crypttab.initramfs. Not sure where you're seeing that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment