Given the decision was made to not support a GUI installer for a long time, Arch Linux has required expert installation knowledge in recent times. This is a collection of scripts based off the official installation guide that help with automating the install of Arch Linux for my particular needs, which are:
- Using a modern and simple desktop environment
- Developing in C#
- Using general image, video, document, and messaging productivity tools
- Using programs that support a security orientation
- Using a discrete NVIDIA GPU to have
- Excellent gaming performance to replace a console
- Excellent video encoding performance to back up optical media
- Using an ASUS motherboard
- Using btrfs to mirror critical data with redundancy
The file and folder structure of the repository is a template of sorts that others may be able to reuse for their needs. Start with modifying common.sh and then modify other files from there.
- A wired internet connection is available and used for the entire process
- The firmware boots in UEFI mode
- A single internal NVMe/SATA disk is the system disk and is wiped in full (pass
-pto preserve/home) - The primary user is the first account created (UID 1000)
- Host-specific values (user, hostname, timezone, mirror country, LAN subnet) are set in
common.sh
- Back up files
- Prepare USB automation drive and UEFI firmware
- Prepare USB installer drive
- Reboot
- Update UEFI firmware
- Configure BIOS and motherboard
- Installation
- Post installation
Two separate USB drives are needed to support the installation process.
Run the following commands on one USB drive.
sudo sgdisk -Z /dev/sdX
sudo sgdisk -n 1:1M:+4G -t 1:8302 -c 1:files /dev/sdX
mkfs.fat -F32 /dev/sdXN
cp -rf arch-linux-setup-scripts <mounted /dev/sdXN>
cp -f *.CAP <mounted /dev/sdXN>
Download the Arch Linux installer ISO image and then use the following commands on the other USB drive.
sudo sgdisk -Z /dev/sdY
sudo dd if=archlinux-x86_64.iso of=/dev/sdY bs=1M status=progress
Within the ASUS UEFI menus, browse to the USB automation drive with the new firmware file to perform the update. This may only be done from a FAT32 filesystem.
A few one-time firmware settings and physical switch changes are needed on the ASUS Pro WS W880-ACE SE.
Change the following from their defaults in the UEFI firmware menus:
- Security > Administrator Password → set. Prevents anyone with physical access from entering Setup to disable Secure Boot, change the boot order, boot external media, or clear the enrolled keys. The PCR 7 seal already refuses to release the TPM-stored LUKS key if the Secure Boot state changes (unlock falls back to the passphrase), so this is defense-in-depth that blocks the tampering rather than merely forcing a passphrase prompt.
- Advanced > CPU Configuration > Total Memory Encryption → Enabled. Turns on Intel Total Memory Encryption. GNOME's built-in Device Security assessment expects this for a hardened system.
- Advanced > APM Configuration > ErP Ready → Enabled (S4+S5). Cuts standby power in the hibernate (S4) and soft-off (S5) states. Without it, the board's firmware wakes the machine moments after it powers down for hibernation, interrupting the cycle and preventing a clean resume.
The following ship enabled by default, but the encrypted, hardware-backed setup depends on them, so confirm they remain enabled:
- Advanced > System Agent (SA) Configuration > VT-d → Enabled. Exposes the Intel IOMMU so the kernel can confine each device's direct memory access. The
intel_iommu=on iommu.strict=1 iommu.passthrough=0parameters in the kernel command line depend on it; together they block DMA attacks that could otherwise read LUKS keys out of RAM while the machine is suspended. This also backs the firmware's pre-boot DMA protection, which guards the window before the kernel's IOMMU takes over (GNOME's Device Security report lists it separately as Pre-boot DMA Protection). After booting, confirm it is active withcat /sys/kernel/iommu_groups/*/type— every group should readDMA, notidentity. - Advanced > PCH-FW Configuration > PTT → Enabled. Turns on Intel Platform Trust Technology, the CPU's built-in firmware TPM 2.0. This presents
/dev/tpmrm0, whichsystemd-cryptenrollcan use to seal a LUKS key to the Secure Boot state, released after a short PIN, in place of typing the full passphrase.
Set the following physical switches on the motherboard while the system is powered off. This board is a server/desktop hybrid, and disabling the unused components shortens boot time:
- Switch 13 (BMC) → off. Disables the onboard baseboard management controller.
- Switch 29 (VGA) → off. Disables the onboard VGA output.
Boot into the live environment with the two USB drives plugged in and then use the following commands to create a bootable system.
If the USB automation drive contains a LUKS partition that needs to be unlocked, it may be done so by doing:
cryptsetup open /dev/sdX cryptusb
Then, instead of using /dev/sdX, use /dev/mapper/cryptusb to mount the device.
cd ~
mkdir files
mount /dev/sdX files
cd files/boot
./install.sh <block device>
cd ~
umount files
arch-chroot /mnt
mount /dev/sdX /mnt
cd /mnt/boot
./bootstrap.sh
exit
reboot
Log in as root. Use the following commands to minimally configure the system and add a GUI desktop.
mount /dev/sdX /mnt
cd /mnt/system
./install.sh
reboot
Reboot into the GNOME login screen and sign in as your user. From a terminal in that graphical session, run the user-level setup, which installs applications, fonts, and desktop settings. Run it inside the graphical session so the GNOME settings apply.
sudo mount /dev/sdX /mnt
cd /mnt/user
./install.sh
The following scripts are optional and run on their own as needed:
system/storage.sh <device> <device>— encrypted btrfs RAID1 data pool (see Configure Storage)system/secure-boot.sh— UEFI Secure Boot signing and key enrollment (see Enable UEFI Secure Boot)system/tpm2-unlock.sh— TPM PIN LUKS unlock via the TPM (see Enable TPM2 Unlock)user/devices/printing.sh— CUPS and HP printer setupuser/packages/ue5.sh— Unreal Engine source buildmaintenance.sh— update the system and prune orphaned packages and cache
This sections contains instructions to follow after a system has been fully restored with most of its configurations and data and is mostly functional.
Bulk data is stored on a btrfs RAID1 mirror layered on LUKS. LUKS underpins both drives; they are unlocked after boot from a keyfile held on the encrypted root (registered in /etc/crypttab with nofail), so a missing drive never stalls startup and no extra passphrase is prompted. btrfs then mirrors the data with end-to-end checksums, so bit rot is detected and self-healed from the good copy.
Because the keyfile lives on the encrypted root, the pool's confidentiality is chained to the root unlock: anything that can read the decrypted root as root can read the keyfile, so /data is gated by the same TPM2-PIN/passphrase unlock rather than an independent secret (each disk still keeps its original passphrase slot as a manual recovery path). Two consequences worth remembering: keep any backup of the root filesystem encrypted, since it contains the data keyfiles under /etc/cryptsetup-keys.d/; and note the LUKS volumes are opened with --allow-discards, leaving TRIM on for SSD longevity at the cost of revealing the used-block map to anyone with raw-disk access (an accepted tradeoff).
Run the following to set up storage. This destroys all data on both devices and prompts you to type the device paths to confirm:
sudo ./system/storage.sh /dev/sdA /dev/sdB
This creates a generic mount point at /data (the top-level btrfs volume) that can be used for anything, scrubbed monthly by btrfs-scrub@data.timer to verify and repair the mirror.
Browse to the GNOME Shell Extensions website, install the GNOME Shell integration browser extension from the banner, and then install the following GNOME Shell extensions:
- ArcMenu
- Dash to Panel
- Night Theme Switcher
- Power Off Options
By default Steam disables GPU accelerated rendering in its web views on NVIDIA. Since the entire client UI--including Big Picture mode--is rendered by the CEF (Chromium) web helper, this forces it to composite in software. On a 4K display that makes the client and Big Picture mode painfully slow. To fix it:
- Open Steam > Settings > Interface.
- Enable Enable GPU accelerated rendering in web views.
- Restart Steam.
secure-boot.sh uses sbctl to create keys and sign the bootloader and the Unified Kernel Images. sbctl installs its own pacman hook that re-signs every tracked EFI binary after kernel and systemd upgrades, so signing stays current without a custom hook. Because bootstrap.sh bundles the kernel, initramfs, microcode, and command line into a single UKI, Secure Boot verifies all of them as one signed unit — closing the gap where a separate initramfs would otherwise load unsigned.
Enrollment keeps Microsoft's keys alongside your custom keys (sbctl enroll-keys -m, paired with the firmware's OS Type = Windows UEFI Mode), preserving the signatures that firmware option ROMs (e.g. the GPU) and the Windows boot manager rely on, so dual-boot and pre-boot hardware keep working. This does not weaken the disk encryption: the TPM seal is bound to which key validated the booted image (PCR 7), so a Microsoft-signed binary measures a different value than your own-key-signed UKI and cannot release the LUKS key.
-
Reboot into UEFI firmware and open
Boot > Secure Boot. -
Set
OS TypetoWindows UEFI Mode. -
Set
Secure Boot ModetoCustom. -
Open
Key Managementand doClear Secure Boot keys. This puts the firmware in Setup Mode, whichsbctl enroll-keys(the-estep below) requires; without it, enrollment fails. -
Exit saving changes and reboot into Linux.
-
Create keys, sign bootloader, and enroll keys:
sudo ./system/secure-boot.sh -e -
Back up private signing keys and store them securely:
sudo tar -C /var/lib/sbctl -czf ~/sbctl-keys.tar.gz keys -
Reboot into Linux.
-
Verify Secure Boot and signing status (see
Verify Secure Bootbelow).
-
Reboot into UEFI firmware and open
Boot > Secure Boot. -
Set
OS TypetoOther OS. -
Exit saving changes and reboot into Linux.
-
Start and finish Linux install process.
-
Import keys and sign bootloader:
tar -xzf ~/sbctl-keys.tar.gz -C /tmp sudo ./system/secure-boot.sh -k /tmp/keys -
Reboot into UEFI firmware and open
Boot > Secure Boot. -
Set
OS TypetoWindows UEFI Mode. -
Exit saving changes and reboot into Linux.
-
Verify Secure Boot and signing status (see
Verify Secure Bootbelow).
If firmware keys were reset or cleared — most often by a BIOS/firmware update — use the first-time enrollment flow again.
sudo bootctl status
sudo sbctl status
sudo sbctl verify
With Secure Boot enabled, the root volume unlocks with a short TPM PIN in place of the full passphrase, by sealing a key to the TPM bound to the Secure Boot state (PCR 7) and released only after the PIN is entered. The TPM's anti-hammering rate-limits PIN guesses, and the LUKS passphrase is kept as a recovery key. The data drives follow automatically since their keyfile lives on the now-unlocked root.
This depends on PTT being enabled (see BIOS and Motherboard Configuration) and Secure Boot being active. Run:
sudo ./system/tpm2-unlock.sh
The script prompts for the existing passphrase (to authorize the new key slot) and for a new PIN to set. PCR 7 is chosen so the seal survives kernel and initramfs updates: the UKI is now also measured into PCR 11, but binding to it would force re-enrollment on every kernel or DKMS rebuild, whereas PCR 7 (the Secure Boot state) is stable across them and still refuses to release the key if Secure Boot is disabled or its keys change. Kernel, DKMS, microcode, and systemd upgrades change none of this, so they need no action. The seal only breaks when the Secure Boot state itself changes — a BIOS/firmware update that resets custom keys, a dbx revocation update, key rotation, or Secure Boot being disabled. When that happens, boot falls back to the passphrase prompt: unlock with the passphrase and re-run this script to re-seal; if the firmware keys themselves were cleared, re-run secure-boot.sh -e first (see Enable UEFI Secure Boot).
The install keeps Linux's hardware clock in UTC (settings.sh runs timedatectl set-local-rtc 0). Windows defaults to treating the RTC as local time, so without matching it the two systems rewrite the clock in different conventions on each boot. Configure Windows to use UTC as well by adding a DWORD named RealTimeIsUniversal, set to 1, under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation. Both operating systems then agree and the clock stays correct across reboots.