| README.md | ||
| simple.txt | ||
| simpler.txt | ||
Arch Linux Encrypted Dual Drive Installation Guide
A comprehensive guide for installing Arch Linux on a UEFI system with full-disk encryption, Btrfs, Secure Boot, and TPM 2.0 auto-unlock.
Overview
Target Configuration:
- NVMe drive (
${ROOT_DISK}): Encrypted system partition with Btrfs subvolumes - SATA SSD (
${DATA_DISK}): Encrypted data storage for media files - Boot method: UEFI direct boot (EFISTUB) with Unified Kernel Image
- Kernel:
linux-hardened(security-hardened kernel with enhanced ASLR and compile-time hardening) - Optional features: Secure Boot, TPM 2.0 auto-unlock, DNS-over-TLS, AppArmor
Both encrypted partitions unlock at boot with a single passphrase via systemd-cryptsetup auto-unlock and optional TPM.
Prerequisites:
- UEFI firmware
- If using Secure Boot: set firmware to Setup Mode before beginning
- If using TPM: ensure TPM 2.0 support
- Single disk installations: ignore all commands referencing
${DATA_DISK}
Back up all important data before proceeding.
Table of Contents
Part 1: Installation
- Prepare the Live Environment
- Partition the Disks
- Encrypt and Format
- Create Btrfs Subvolumes
- Mount Filesystems
- Install Base System
- Configure the System
- Configure Networking
- Configure Boot
- Secure Boot Setup (Optional)
- Reboot
- TPM Enrollment (Optional)
- Post-Installation Setup
Part 2: System Hardening and Optimization
- Security Hardening
- Performance Tuning
- Hardware Optimization
- Audio Configuration
- Power Management
- Optional Enhancements
Appendices
- Appendix A: Btrfs Reference
- Appendix B: Package Purposes
- Appendix C: Boot Configuration Reference
- Appendix D: Sysctl Reference
Part 1: Installation
1. Prepare the Live Environment
1.1 Set Keyboard Layout
loadkeys br-abnt2
Replace br-abnt2 with the appropriate layout.
1.2 Connect to Wi-Fi
Identify the wireless interface:
ip link
Unblock Wi-Fi and bring the interface up:
rfkill unblock wifi
ip link set wlan0 up
Replace wlan0 with the actual interface name.
Connect using iwctl:
iwctl
Inside iwctl:
station wlan0 scan
station wlan0 get-networks
station wlan0 connect YOUR_WIFI_SSID
exit
Verify connectivity:
ping -c3 archlinux.org
1.3 Synchronize System Clock
timedatectl set-ntp true
2. Partition the Disks
2.1 Identify and Export Disk Paths
lsblk
Export drive paths:
export ROOT_DISK="/dev/nvme0n1"
export DATA_DISK="/dev/sda"
Note: NVMe partition references use p notation (${ROOT_DISK}p1, ${ROOT_DISK}p2). SATA/SCSI references do not (${DATA_DISK}1).
2.2 Wipe Existing Partition Tables
sgdisk -Z ${ROOT_DISK}
sgdisk -Z ${DATA_DISK}
2.3 Partition the NVMe (System Disk)
gdisk ${ROOT_DISK}
o
Y
n
<Enter>
<Enter>
+512M
ef00
c
ESP
n
<Enter>
<Enter>
<Enter>
8304
c
2
ROOT
w
Y
2.4 Partition the SATA SSD (Data Disk)
gdisk ${DATA_DISK}
o
Y
n
<Enter>
<Enter>
<Enter>
8309
c
DATA
w
Y
Partition types: ef00 is the EFI System Partition. 8304 is Linux root (x86-64), the correct type for the encrypted system partition per the Discoverable Partitions Specification (DPS) — systemd-gpt-auto-generator and related tooling use this type to identify the root partition's role. 8309 is the generic Linux LUKS type used for the data disk, which has no DPS-governed role.
2.5 Reload Partition Tables
partprobe -s ${ROOT_DISK}
partprobe -s ${DATA_DISK}
3. Encrypt and Format
3.1 Wipe Drives Before Encryption
For NVMe drives, perform a cryptographic erase using the drive controller. Install the required tool from the live environment:
pacman -Sy nvme-cli
Then erase:
nvme format --ses=1 ${ROOT_DISK}
This resets the drive's internal encryption key, rendering all existing data cryptographically inaccessible. It completes in seconds regardless of drive capacity.
For SATA SSDs, do not overwrite with random data if TRIM will be used — the first TRIM command will undo any overwrite. Proceed directly to formatting; the LUKS encryption layer makes prior data cryptographically inaccessible.
3.2 Encrypt Partitions
Encrypt the root partition:
cryptsetup luksFormat --sector-size 4096 ${ROOT_DISK}p2
cryptsetup open ${ROOT_DISK}p2 cryptroot
Encrypt the data partition:
cryptsetup luksFormat --sector-size 4096 ${DATA_DISK}1
cryptsetup open ${DATA_DISK}1 cryptdata
--sector-size 4096 aligns the LUKS container to 4096-byte sectors. Many consumer SSDs misreport 512-byte logical sectors despite having 4096-byte physical sectors; this flag ensures correct alignment regardless. The --hash flag is intentionally omitted: in LUKS2 with argon2id, --hash controls only the AF-splitter digest used to protect key material, not argon2id's internal function (which is BLAKE2b regardless). SHA-256 provides sufficient collision resistance for this purpose; SHA-512 adds no meaningful security.
Note: Performance flags (no-read-workqueue, no-write-workqueue, discard) are set in /etc/crypttab.initramfs (see Section 9.6), which is the authoritative source for boot-time behavior.
3.3 Verify the LUKS Containers
cryptsetup luksDump ${ROOT_DISK}p2
cryptsetup luksDump ${DATA_DISK}1
Confirm: LUKS version 2, cipher aes-xts-plain64, PBKDF argon2id, sector size 4096.
3.4 Back Up LUKS Headers
The LUKS header stores the encrypted master key. Its loss means permanent data loss regardless of knowing the passphrase.
cryptsetup luksHeaderBackup ${ROOT_DISK}p2 --header-backup-file cryptroot-header.img
cryptsetup luksHeaderBackup ${DATA_DISK}1 --header-backup-file cryptdata-header.img
Store these files on offline physical media, separately from the passphrase.
3.5 Format Filesystems
ESP:
mkfs.fat -F32 -n ESP ${ROOT_DISK}p1
Root partition:
mkfs.btrfs -L ROOT /dev/mapper/cryptroot
Data partition:
mkfs.btrfs -L DATA /dev/mapper/cryptdata
Note on checksums: Btrfs uses crc32c by default, which is sufficient for error detection given the dm-crypt encryption layer above it. Since kernel 5.5, xxhash is available via mkfs.btrfs --checksum xxhash. It is both faster than crc32c and has better collision resistance, with no compatibility drawbacks on kernels ≥ 5.5. The tradeoff is that the filesystem cannot be mounted on older kernels or tools. This choice is irreversible and must be made at format time.
4. Create Btrfs Subvolumes
Mount the root filesystem temporarily:
mount /dev/mapper/cryptroot /mnt
Create subvolumes using a flat layout:
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@var
btrfs subvolume create /mnt/@snapshots
Unmount:
umount /mnt
See Appendix A for subvolume layout details.
5. Mount Filesystems
5.1 Understanding Btrfs Mount Options
Most Btrfs-specific options are filesystem-wide: they apply from the first mount and are inherited by all subsequent subvolume mounts. noatime is a VFS-level option and must be specified per-mount. discard=async and space_cache=v2 are both kernel defaults and do not need to be specified. See Appendix A.2.
5.2 Mount Root Subvolume
mount -o noatime,compress=zstd:2,subvol=@ /dev/mapper/cryptroot /mnt
5.3 Create Mount Points
mkdir -p /mnt/{home,var,snapshots,efi,data}
5.4 Mount Remaining Subvolumes
mount -o noatime,subvol=@home /dev/mapper/cryptroot /mnt/home
mount -o noatime,subvol=@var /dev/mapper/cryptroot /mnt/var
mount -o noatime,subvol=@snapshots /dev/mapper/cryptroot /mnt/snapshots
5.5 Mount ESP and Data
mount ${ROOT_DISK}p1 /mnt/efi
mount -o noatime,compress=zstd:2 /dev/mapper/cryptdata /mnt/data
6. Install Base System
6.1 Update Mirrorlist
reflector -c "XX,YY" -f 5 -a 24 -p https --save /etc/pacman.d/mirrorlist --verbose
Replace XX,YY with the country codes for the two countries geographically closest to the system's location. The -c flag restricts mirrors to those countries, reducing latency. -f 5 selects the five fastest mirrors, -a 24 excludes mirrors not synchronized within 24 hours, and -p https restricts to HTTPS mirrors.
6.2 Install Packages
pacstrap -i -K /mnt base base-devel linux-hardened linux-hardened-headers linux-firmware \
cryptsetup efibootmgr amd-ucode btrfs-progs sof-firmware \
iwd systemd-resolvconf chrony wireless-regdb iptables-nft nftables \
sbctl tpm2-tools tpm2-tss zram-generator apparmor vim git bash-completion
Kernel alternatives: linux-hardened provides a security-hardened kernel with enhanced ASLR, more restrictive compile-time defaults, and an additional kernel patch set. For a performance-oriented kernel without these restrictions, replace with linux-zen.
Package variations:
- Intel CPU: replace
amd-ucodewithintel-ucode - Without Secure Boot: omit
sbctl - Without TPM: omit
tpm2-toolsandtpm2-tss - Without firewall: omit
iptables-nftandnftables - Without AppArmor: omit
apparmor
See Appendix B for package explanations.
6.3 Generate fstab
genfstab -U /mnt >> /mnt/etc/fstab
Verify the output and make the following corrections manually:
- Confirm no
discardoption appears on Btrfs entries (Btrfs async discard is a kernel default; see Appendix A.3) - Add
noexec,nodev,nosuid,nosymfollow,fmask=0137,dmask=0027to the ESP entry options (genfstab includes neither):noexec,nodev,nosuid,nosymfollow: required by the Boot Loader Specification for all ESP mounts from Linux; prevent execution of files from the FAT32 partition, block device file interpretation, setuid escalation, and symlink traversal attacksfmask=0137: files on the ESP get permissionsrw-r-----— owner (root) can read/write, group can read, others have no accessdmask=0027: directories getrwxr-x---— owner has full access, group can traverse and list, others have no access
- Confirm ESP
passfield is2; all other entries should be0
6.4 Preload VFAT Modules
Create a module preload configuration to ensure ESP filesystem modules are available, preventing boot failures after kernel updates:
cat > /mnt/etc/modules-load.d/vfat.conf << 'EOF'
vfat
nls_cp437
nls_ascii
EOF
7. Configure the System
Enter the chroot environment:
arch-chroot /mnt bash
7.1 Timezone and Clock
ln -sf /usr/share/zoneinfo/Region/City /etc/localtime
hwclock --systohc
7.2 Locale
vim /etc/locale.gen
Uncomment the desired locale (e.g., en_US.UTF-8 UTF-8), then generate:
locale-gen
cat > /etc/locale.conf << 'EOF'
LANG=en_US.UTF-8
LC_COLLATE=C
EOF
7.3 Console Keymap
echo "KEYMAP=xx" > /etc/vconsole.conf
Replace xx with the keymap matching the keyboard layout used in the live environment (Section 1.1). Available keymaps can be listed with localectl list-keymaps.
7.4 Hostname and Hosts
echo "arch" > /etc/hostname
cat > /etc/hosts << 'EOF'
127.0.0.1 localhost
127.0.1.1 arch.localdomain arch
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
Replace arch with the configured hostname.
7.5 Password Hashing Strength
Configure before creating user accounts:
vim /etc/login.defs
Find and set:
YESCRYPT_COST_FACTOR 8
Note: This applies only to passwords set after this change. Existing passwords must be reset with passwd username to use the new cost factor.
7.6 Create User
useradd -mG wheel username
passwd username
passwd
Enable sudo for the wheel group:
EDITOR=vim visudo
Uncomment:
%wheel ALL=(ALL:ALL) ALL
8. Configure Networking
8.1 Enable Network Services
systemctl enable systemd-networkd systemd-resolved iwd nftables chronyd apparmor auditd
Services enabled:
systemd-networkd: network management (DHCP, interface configuration)systemd-resolved: DNS resolver with DNSSEC and DNS-over-TLSiwd: wireless daemonnftables: stateful packet filter firewallchronyd: NTP/NTS time synchronizationapparmor: mandatory access controlauditd: kernel audit daemon; logs privileged operations and AppArmor denials to/var/log/audit/audit.log
8.2 iwd Configuration
mkdir -p /etc/iwd
cat > /etc/iwd/main.conf << 'EOF'
[General]
AddressRandomization=network
AddressRandomizationRange=full
DisableANQP=true
[DriverQuirks]
PowerSaveDisable=*
EOF
Settings:
AddressRandomization=network: generates a stable MAC per SSID derived from the SSID and permanent adapter address — the same MAC is used on reconnection to a known network, preventing tracking while maintaining DHCP lease stabilityAddressRandomizationRange=full: randomizes all six octets and sets the locally-administered bitDisableANQP=true: disables Hotspot 2.0 ANQP queries that passively disclose network preferencesPowerSaveDisable=*: disables power saving for all adapters (improves stability)
Note: EnableNetworkConfiguration is intentionally absent (defaults to disabled). systemd-networkd manages all IP configuration. The journal entry station: Network configuration is disabled is expected and correct.
8.3 Network Configuration
Wi-Fi:
cat > /etc/systemd/network/20-wifi.network << 'EOF'
[Match]
Type=wlan
[Network]
DHCP=yes
IPv6PrivacyExtensions=true
IPv6LinkLocalAddressGenerationMode=stable-privacy
IgnoreCarrierLoss=3s
LLDP=false
EmitLLDP=false
[DHCPv4]
Anonymize=true
UseDomains=false
[DHCPv6]
UseDomains=false
EOF
Ethernet:
cat > /etc/systemd/network/20-wired.network << 'EOF'
[Match]
Type=ether
Kind=!*
[Link]
RequiredForOnline=no
[Network]
DHCP=yes
IPv6PrivacyExtensions=true
IPv6LinkLocalAddressGenerationMode=stable-privacy
LLDP=false
EmitLLDP=false
[DHCPv4]
Anonymize=true
UseDomains=false
[DHCPv6]
UseDomains=false
EOF
MAC Randomization (wired):
cat > /etc/systemd/network/01-mac.link << 'EOF'
[Match]
Type=ether
Kind=!*
[Link]
MACAddressPolicy=random
EOF
Settings:
Kind=!*in the wired match and link file: excludes virtual Ethernet interfaces (bridges, bonds, libvirt NAT interfaces, VLANs) which should not be managed as physical linksRequiredForOnline=no: prevents a 2-minute boot delay when the wired interface is not connectedIPv6LinkLocalAddressGenerationMode=stable-privacy: generates a stable but non-trackable link-local IPv6 address; without this, the link-local address is derived from the hardware MAC (EUI-64), exposing the permanent address in every IPv6 packet regardless ofIPv6PrivacyExtensionsLLDP=false/EmitLLDP=false: disables Link Layer Discovery Protocol reception and transmission, preventing passive network topology disclosureUseDomains=false: prevents DHCP-pushed DNS search domains from being registered as routing domains or overriding configured DNS
Note: iwd handles wireless MAC randomization natively via AddressRandomization in main.conf. The .link file is scoped to wired only — attempting to apply MACAddressPolicy to a wireless interface managed by iwd fails with a "Device or resource busy" error because iwd claims the interface before udev can act on it.
8.4 Wireless Regulatory Domain
vim /etc/conf.d/wireless-regdom
Uncomment the appropriate country code:
WIRELESS_REGDOM="XX"
Note: Setting the correct country code restricts the wireless driver to legal channel and transmit power limits for the jurisdiction. An incorrect or absent setting may permit operation on illegal frequencies or at illegal power levels.
8.5 DNS-over-TLS (systemd-resolved)
mkdir -p /etc/systemd/resolved.conf.d
cat > /etc/systemd/resolved.conf.d/dns.conf << 'EOF'
[Resolve]
DNS=94.140.14.14#dns.adguard-dns.com 94.140.15.15#dns.adguard-dns.com 2a10:50c0::ad1:ff#dns.adguard-dns.com 2a10:50c0::ad2:ff#dns.adguard-dns.com
FallbackDNS=9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net
DNSOverTLS=yes
DNSSEC=yes
Domains=~.
MulticastDNS=no
LLMNR=no
StaleRetentionSec=86400
EOF
Settings:
DNS=: primary DNS servers; formatIP#hostnameenables certificate validation for DNS-over-TLSFallbackDNS=: backup servers used if all primary servers are unreachableDNSOverTLS=yes: enforces encrypted DNS transport; fails if the server does not support TLSDNSSEC=yes: validates DNSSEC signatures; rejects responses that fail validationDomains=~.: routes all DNS queries through the configured servers, overriding any DHCP-provided DNSMulticastDNS=no/LLMNR=no: disables mDNS and Link-Local Multicast Name ResolutionStaleRetentionSec=86400: serves cached records for up to 24 hours if upstream is unreachable
8.6 Time Synchronization (chrony with NTS)
Replace the contents of /etc/chrony.conf with:
cat > /etc/chrony.conf << 'EOF'
# NTS servers
server gps.ntp.br iburst nts
server a.st1.ntp.br iburst nts
server b.st1.ntp.br iburst nts
server time.cloudflare.com iburst nts
# Authentication policy
authselectmode require
minsources 2
# Clock correction
makestep 1.0 3
leapseclist /usr/share/zoneinfo/leap-seconds.list
# Drift and state files
driftfile /var/lib/chrony/drift
dumpdir /var/lib/chrony
ntsdumpdir /var/lib/chrony
# RTC tracking
rtcfile /var/lib/chrony/rtc
rtcautotrim 30
rtconutc
# Disable remote command port
cmdport 0
EOF
Settings:
server ... nts: NTS-capable NTP servers with authenticated, encrypted time synchronizationiburst: sends a burst of packets on startup for faster initial synchronizationauthselectmode require: enforces that all sources use NTS; unauthenticated sources are automatically excluded from selectionminsources 2: requires at least two sources to agree before updating the clockmakestep 1.0 3: allows a step correction in the first three updates to handle large initial clock errors (e.g., laptop booting after extended powered-off period)ntsdumpdir: saves NTS session keys/cookies between restarts, avoiding a full handshake on each bootrtcfile/rtcautotrim/rtconutc: tracks RTC drift and keeps it synchronized, assuming RTC keeps UTC timecmdport 0: disables the UDP command port; localchronycaccess still works via Unix socket
Note: Remove rtconutc when dual-booting with Windows, which sets the RTC to local time.
Create the chronyd arguments file:
mkdir -p /etc/sysconfig
echo "OPTIONS='-r -s'" > /etc/sysconfig/chronyd
-r: restores saved state from dumpdir on startup; -s: steps the clock from the RTC on startup.
8.7 Journal Size Limits
mkdir -p /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/size.conf << 'EOF'
[Journal]
SystemMaxUse=500M
SystemKeepFree=1G
RuntimeMaxUse=100M
MaxFileSec=1month
EOF
8.8 Configure resolv.conf
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
The target path does not need to exist at creation time; it will be present once systemd-resolved starts after the first boot.
8.9 Firewall Configuration
The default /etc/nftables.conf shipped with the nftables package is already a stateful drop-by-default ruleset. No modification is required.
Verify the content reflects a drop policy on the input chain:
cat /etc/nftables.conf
Note: If SSH is enabled (see Section 14.9), add tcp dport ssh accept before the rate-limit line in the input chain.
9. Configure Boot
9.1 Create UKI Directory
mkdir -p /efi/EFI/Linux
9.2 Configure UKI Preset
Edit the preset file:
vim /etc/mkinitcpio.d/linux-hardened.preset
Set the following:
ALL_kver="/boot/vmlinuz-linux-hardened"
PRESETS=('default')
default_uki="/efi/EFI/Linux/arch-linux-hardened.efi"
Note: The absence of ALL_config enables drop-in configuration files from /etc/mkinitcpio.conf.d/ (required for mkinitcpio ≥ 36).
9.3 Configure mkinitcpio
vim /etc/mkinitcpio.conf
Set:
MODULES=(tpm_crb amdgpu)
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)
MODULES:
tpm_crb: required beforesd-encryptruns so that the TPM 2.0 device is available for automatic unlock during early bootamdgpu: ensures the display is active during the LUKS password prompt via early KMS;kmshook uses autodetect but explicit listing guarantees inclusion
HOOKS notes:
modconfincludes all files from/etc/modprobe.d/into the initramfs — the module blacklists and options configured in Part 2 take effect from the earliest boot stage- The
btrfshook is intentionally absent; it is only required for multi-device Btrfs configurations. Thefilesystemshook is sufficient for a single-device Btrfs root sd-vconsolereplaces the legacykeymapandconsolefonthooks; do not use both- Hook order is significant; do not rearrange without understanding dependencies
If not using TPM: omit tpm_crb from MODULES.
If using a different GPU: replace amdgpu with the appropriate module (e.g., i915 for Intel).
9.4 Get UUIDs
ROOT_PART_UUID=$(blkid -s UUID -o value ${ROOT_DISK}p2)
DATA_PART_UUID=$(blkid -s UUID -o value ${DATA_DISK}1)
ROOT_FS_UUID=$(blkid -s UUID -o value /dev/mapper/cryptroot)
9.5 Create Kernel Command Line
cat > /etc/kernel/cmdline << EOF
rd.luks.name=${ROOT_PART_UUID}=cryptroot rd.luks.name=${DATA_PART_UUID}=cryptdata root=UUID=${ROOT_FS_UUID} rootflags=subvol=@ rw lsm=landlock,lockdown,yama,integrity,apparmor,bpf lockdown=integrity amd_pstate=active iommu=pt sysrq_always_enabled=1 zswap.enabled=0 nowatchdog
EOF
See Appendix C for parameter explanations.
9.6 Create Crypttab
cat > /etc/crypttab.initramfs << EOF
cryptroot UUID=${ROOT_PART_UUID} none discard,timeout=120s,tries=5,password-echo=no,no-read-workqueue,no-write-workqueue,x-initrd.attach
cryptdata UUID=${DATA_PART_UUID} none discard,timeout=120s,tries=5,password-echo=no,no-read-workqueue,no-write-workqueue
EOF
Key options:
discard: passes TRIM requests through the dm-crypt layer to the underlying SSD; required for Btrfs async discard to function through the encryption boundary (see Appendix A.3)no-read-workqueue/no-write-workqueue: bypass the dm-crypt internal workqueue, processing requests synchronously; reduces latency on SSDs where queue overhead exceeds benefit (requires kernel ≥ 5.9)timeout=120s: password entry timeout (0 waits indefinitely)tries=5: maximum password attemptspassword-echo=no: suppresses all password feedback;masked(the default) echoes asterisksx-initrd.attach: keeps the encrypted root device open during shutdown; prevents systemd from attempting to detach it while still in use; not required forcryptdata
Security note: discard leaks information about which storage blocks contain data. For high-security threat models, remove discard from both entries and rely on periodic fstrim alone.
See Appendix C.2 for all options.
9.7 Generate Initramfs
mkinitcpio -P
This creates /efi/EFI/Linux/arch-linux-hardened.efi.
9.8 Create EFISTUB Boot Entry
efibootmgr -d ${ROOT_DISK} -p 1 -c -L "Arch Linux" -l '\EFI\Linux\arch-linux-hardened.efi' -v
The UEFI firmware loads and boots the UKI .efi file directly via the kernel's built-in EFI stub, without an intermediate bootloader.
10. Secure Boot Setup (Optional)
10.1 Check Status
sbctl status
10.2 Create and Enroll Keys
sbctl create-keys
sbctl enroll-keys -m -f
-m: includes Microsoft UEFI certificates for hardware firmware compatibility-f: includes OEM firmware certificates to preserve firmware update capability
Note: -f may fail on systems without OEM certificates. Remove it and retry if that occurs.
10.3 Sign UKI
sbctl sign -s /efi/EFI/Linux/arch-linux-hardened.efi
The -s flag registers the path in sbctl's database. The included pacman hook uses this database to automatically re-sign updated UKIs on every kernel update, maintaining Secure Boot without manual intervention.
10.4 Verify
sbctl verify
11. Reboot
Exit chroot:
exit
Sync and reboot:
sync
systemctl reboot --firmware-setup
Before booting:
- If using Secure Boot: enable it in firmware settings
- Remove installation media
- Set boot order to prioritize the "Arch Linux" entry
First boot: enter the LUKS passphrase when prompted. Verify network connectivity after login: ping archlinux.org.
12. TPM Enrollment (Optional)
TPM enrollment configures the TPM 2.0 chip to automatically provide the LUKS unlock key when the system boots with verified firmware and a signed kernel. Manual passphrase entry is still required as a fallback.
Prerequisites: Secure Boot must be fully configured and active before TPM enrollment. PCR 7 (Secure Boot state) is used as part of the unlock policy.
12.1 Export Volume Paths
export ROOT_DISK="/dev/nvme0n1"
export DATA_DISK="/dev/sda"
export ROOT_PART_UUID=$(blkid -s UUID -o value ${ROOT_DISK}p2)
export DATA_PART_UUID=$(blkid -s UUID -o value ${DATA_DISK}1)
12.2 Create Recovery Keys
These are fallback keys stored in separate LUKS keyslots. They allow access if the passphrase is forgotten or the TPM fails.
systemd-cryptenroll --recovery-key ${ROOT_DISK}p2
systemd-cryptenroll --recovery-key ${DATA_DISK}1
Store the displayed recovery keys on offline physical media. Without them, TPM failure combined with a forgotten passphrase means permanent data loss.
12.3 Enroll TPM
Enroll both volumes using PCR 7 (Secure Boot policy) and PCR 15 (volume key measurement):
systemd-cryptenroll \
--tpm2-device=auto \
--tpm2-pcrs=7+15:sha256=0000000000000000000000000000000000000000000000000000000000000000 \
--tpm2-with-pin=yes \
${ROOT_DISK}p2
systemd-cryptenroll \
--tpm2-device=auto \
--tpm2-pcrs=7+15:sha256=0000000000000000000000000000000000000000000000000000000000000000 \
--tpm2-with-pin=yes \
${DATA_DISK}1
PCR policy explanation:
PCR 7binds the key to the current Secure Boot state. If Secure Boot is disabled or keys are changed, the TPM will refuse to unlock.PCR 15starts at all zeros and is extended bysystemd-cryptsetupwith a hash of the volume key immediately after unlock. The all-zero prediction means: unlock only if PCR 15 has not yet been extended — i.e., only during the first (legitimate) boot unlock. This prevents replay attacks.--tpm2-with-pin=yesrequires a PIN in addition to the correct PCR state; the TPM-PIN combination forms a two-factor unlock. The PIN is separate from the LUKS passphrase.
If not using Secure Boot, use PCR 15 alone:
systemd-cryptenroll \
--tpm2-device=auto \
--tpm2-pcrs=15:sha256=0000000000000000000000000000000000000000000000000000000000000000 \
--tpm2-with-pin=yes \
${ROOT_DISK}p2
12.4 Update Crypttab
Edit /etc/crypttab.initramfs and add TPM options to both entries:
cryptroot UUID=<ROOT_PART_UUID> none discard,timeout=120s,tries=5,password-echo=no,no-read-workqueue,no-write-workqueue,x-initrd.attach,tpm2-device=auto,tpm2-measure-pcr=yes
cryptdata UUID=<DATA_PART_UUID> none discard,timeout=120s,tries=5,password-echo=no,no-read-workqueue,no-write-workqueue,tpm2-device=auto,tpm2-measure-pcr=yes
New options:
tpm2-device=auto: automatically discovers the TPM 2.0 device; specify a path (e.g.,/dev/tpmrm0) only when multiple TPMs are presenttpm2-measure-pcr=yes: extends PCR 15 with a hash of the volume key after successful unlock, establishing the PCR 15 policy used at enrollment
12.5 Back Up Updated LUKS Headers
TPM enrollment adds a new keyslot to the LUKS header. The header has changed since the initial backup in Section 3.4. Create updated backups:
cryptsetup luksHeaderBackup ${ROOT_DISK}p2 --header-backup-file cryptroot-header-post-tpm.img
cryptsetup luksHeaderBackup ${DATA_DISK}1 --header-backup-file cryptdata-header-post-tpm.img
12.6 Regenerate Initramfs and Re-sign
Renegerating the initramfs will now automatically hook Secure Boot resigning with sbctl
mkinitcpio -P
12.7 Reboot and Test
systemctl reboot
The system should prompt for the TPM PIN and then unlock automatically. If the PIN is unknown or TPM unlock fails, the system falls back to the passphrase.
12.8 Fixate Volume Key (Optional)
After a successful TPM-unlocked boot, extract the volume key hashes from the TPM measurement log:
grep 'volume-key' /run/log/systemd/tpm2-measure.log | grep -o '[0-9a-f]\{64\}'
This outputs two SHA-256 digests on separate lines: the first corresponds to cryptroot, the second to cryptdata, in unlock order.
Add fixate-volume-key=<digest> to the corresponding entry in /etc/crypttab.initramfs:
cryptroot UUID=<ROOT_PART_UUID> none ...,fixate-volume-key=<cryptroot-sha256-digest>
cryptdata UUID=<DATA_PART_UUID> none ...,fixate-volume-key=<cryptdata-sha256-digest>
This pins the expected volume key hash. If a rogue operating system attempts to impersonate the root partition using copied partition UUIDs and metadata, it will have a different volume key and unlock will be refused. Requires systemd ≥ 260.
Note: If the volume is ever re-encrypted with cryptsetup reencrypt, the volume key changes. The crypttab entries must be updated with the new hashes.
Regenerate the initramfs after updating crypttab:
mkinitcpio -P
13. Post-Installation Setup
13.1 Install Additional Packages
pacman -S mesa vulkan-radeon libva-mesa-driver tlp \
pipewire pipewire-pulse pipewire-alsa pipewire-jack wireplumber \
xdg-desktop-portal xdg-desktop-portal-wlr xdg-desktop-portal-gtk
Package variations:
- Intel GPU: replace
vulkan-radeonwithvulkan-intel, replacelibva-mesa-driverwithintel-media-driver libva-mesa-driver: VA-API hardware video decoding for AMD GPUs (MPEG-2, H.264, H.265, AV1 depending on GPU generation)
13.2 Enable TLP service
systemctl enable tlp
systemctl mask systemd-rfkill.service systemd-rfkill.socket
TLP manages radio device power state. systemd-rfkill must be masked to prevent conflicts.
13.3 Configure Zram
mkdir -p /etc/systemd/zram-generator.conf.d
cat > /etc/systemd/zram-generator.conf.d/zram.conf << 'EOF'
[zram0]
compression-algorithm = zstd
zram-size = min(ram / 2)
EOF
compression-algorithm = zstd is the current kernel default and is set explicitly to ensure consistent behavior if the default changes in a future kernel. The zram-generator default caps the device at 4096 MB regardless of available RAM — appropriate for low-memory systems but too conservative for systems with 16 GB or more. min(ram / 2) with a single argument removes the cap, creating a device of half the installed RAM unconditionally. The kernel documentation notes values up to twice physical RAM are reasonable given typical compression ratios; half is a conservative and widely-used baseline.
Advanced compression: For systems where minimizing swap latency is critical, a two-tier algorithm can be used:
compression-algorithm = lzo-rle zstd(level=3) (type=idle)
lzo-rle is the primary algorithm for active pages — faster compression and decompression, lower latency under pressure. zstd(level=3) is the recompression algorithm applied to idle pages in the background, achieving a better compression ratio at higher CPU cost. (type=idle) is a global recompression parameter that restricts recompression to idle pages only; active pages are never recompressed. Requires kernel ≥ 6.2 with CONFIG_ZRAM_MULTI_COMP.
13.4 Enable Periodic TRIM
systemctl enable fstrim.timer
Btrfs async discard (kernel default) continuously sends TRIM commands for freed blocks through the dm-crypt discard gate. The weekly fstrim sweep complements this by catching any missed blocks and handling the ESP, which has no async discard mechanism. See Appendix A.3 for a full explanation of how these mechanisms interact.
13.5 AppArmor Profile Cache
Enabling profile caching significantly reduces boot time by avoiding recompilation of profiles on each start:
vim /etc/apparmor/parser.conf
Uncomment:
write-cache
After the next boot, verify profiles loaded correctly:
sudo aa-status
Expected output: 100+ profiles loaded, the majority in enforce mode.
Part 2: System Hardening and Optimization
14. Security Hardening
14.1 Core Security Sysctl
cat > /etc/sysctl.d/99-security.conf << 'EOF'
# Kernel hardening
kernel.kptr_restrict = 2
kernel.perf_event_paranoid = 3
kernel.kexec_load_disabled = 1
kernel.unprivileged_userfaultfd = 0
kernel.panic = 10
kernel.oops_limit = 100
kernel.warn_limit = 100
kernel.printk = 3 3 3 3
dev.tty.ldisc_autoload = 0
# Filesystem hardening
fs.suid_dumpable = 0
fs.protected_regular = 2
fs.protected_fifos = 2
# Network security
net.ipv4.tcp_rfc1337 = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.default.use_tempaddr = 2
net.ipv4.tcp_timestamps = 0
EOF
Settings reference: Appendix D.1. For settings considered but intentionally not applied, see Appendix D.3.
14.2 Linux-Hardened Specific Settings
The linux-hardened kernel sets kexec_load_disabled and unprivileged_userfaultfd to secure values by default via kernel config. The entries above make those defaults explicit and portable. The following setting is linux-hardened specific and does not exist in mainline kernels:
cat > /etc/sysctl.d/99-linux-hardened.conf << 'EOF'
# linux-hardened disables unprivileged user namespaces by default.
# Required for: Steam sandbox, bubblewrap, Flatpak, browser renderer isolation.
kernel.unprivileged_userns_clone = 1
EOF
Note: This sysctl key does not exist on mainline or zen kernels. If switching kernels, remove this file.
14.3 Disable Unused Modules
cat > /etc/modprobe.d/99-blacklist.conf << 'EOF'
install sp5100_tco /bin/false
install wdat_wdt /bin/false
install pcspkr /bin/false
EOF
Using install module /bin/false rather than blacklist module prevents even explicit modprobe invocation, not just autoloading. The modconf mkinitcpio hook includes this file in the initramfs, so these restrictions take effect from the first module-loading phase.
14.4 Disable Unused Network Protocols
cat > /etc/modprobe.d/network-protocols.conf << 'EOF'
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
install n-hdlc /bin/false
install ax25 /bin/false
install netrom /bin/false
install x25 /bin/false
install rose /bin/false
install decnet /bin/false
install econet /bin/false
install af_802154 /bin/false
install ipx /bin/false
install appletalk /bin/false
install psnap /bin/false
install p8023 /bin/false
install p8022 /bin/false
install can /bin/false
install atm /bin/false
EOF
14.5 Disable Unused Filesystems and Hardware
cat > /etc/modprobe.d/unused-modules.conf << 'EOF'
# Unused filesystems
install cramfs /bin/false
install freevxfs /bin/false
install jffs2 /bin/false
install gfs2 /bin/false
install reiserfs /bin/false
install jfs /bin/false
install minix /bin/false
install sysv /bin/false
# FireWire (DMA attack vector)
install firewire-core /bin/false
install firewire-ohci /bin/false
install firewire_sbp2 /bin/false
install firewire-net /bin/false
install ohci1394 /bin/false
install sbp2 /bin/false
install dv1394 /bin/false
install raw1394 /bin/false
install video1394 /bin/false
# Test and GNSS drivers
install vivid /bin/false
install gnss /bin/false
install gnss-mtk /bin/false
install gnss-serial /bin/false
install gnss-sirf /bin/false
install gnss-usb /bin/false
install gnss-ubx /bin/false
# Legacy hardware
install floppy /bin/false
install parport /bin/false
install parport_pc /bin/false
install pcmcia /bin/false
install yenta_socket /bin/false
EOF
14.6 Disable Legacy Framebuffer Drivers
cat > /etc/modprobe.d/framebuffer.conf << 'EOF'
blacklist cyber2000fb
blacklist cyblafb
blacklist gx1fb
blacklist hgafb
blacklist lxfb
blacklist matroxfb_base
blacklist neofb
blacklist pm2fb
blacklist s1d13xxxfb
blacklist sisfb
blacklist tdfxfb
blacklist tridentfb
blacklist udlfb
blacklist vfb
blacklist vesafb
blacklist vt8623fb
EOF
14.7 Regenerate Initramfs
The modconf hook must pick up the new modprobe.d files:
mkinitcpio -P
14.8 Default umask (Optional)
Changing the system-wide default umask to 027 restricts new file permissions so that group members have read/execute access but no world access:
vim /etc/login.defs
Set:
UMASK 027
Note: A umask of 027 can break some applications that expect world-readable files in shared paths. Test on a non-critical system before applying broadly. The system default of 022 is appropriate if any issues arise.
14.9 SSH Configuration (Optional)
Only enable sshd if remote access is required. Enabling it on a system not intended for remote access increases attack surface without benefit.
Harden the SSH daemon configuration:
vim /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
AuthenticationMethods publickey
X11Forwarding no
AllowTcpForwarding no
PrintMotd no
Add an SSH accept rule to nftables before the rate-limit line in the input chain:
vim /etc/nftables.conf
Add before pkttype host limit rate:
tcp dport ssh accept comment "allow SSH"
Enable:
systemctl enable --now sshd
Generate and deploy keys from the client machine:
ssh-keygen -t ed25519 -C "user@hostname"
ssh-copy-id -i ~/.ssh/id_ed25519.pub username@server
15. Performance Tuning
15.1 TCP and Network Performance
cat > /etc/sysctl.d/99-performance.conf << 'EOF'
# TCP improvements
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_congestion_control = bbr
net.ipv4.ip_local_port_range = 30000 65535
net.core.netdev_max_backlog = 4096
# Filesystem
fs.inotify.max_user_instances = 8192
# Memory management
vm.compaction_proactiveness = 0
vm.min_free_kbytes = 614400
vm.vfs_cache_pressure = 40
vm.page_lock_unfairness = 1
# Memory writeback
vm.dirty_background_bytes = 268435456
vm.dirty_bytes = 536870912
vm.dirty_writeback_centisecs = 1000
# Applications requiring large memory maps (games)
vm.max_map_count = 2147483642
EOF
Settings reference: Appendix D.4.
15.2 BBR Module
Ensure tcp_bbr loads at boot:
echo "tcp_bbr" > /etc/modules-load.d/tcp_bbr.conf
15.3 Zram Sysctl
cat > /etc/sysctl.d/99-vm-zram.conf << 'EOF'
# Zram-optimized swap parameters
vm.swappiness = 180
vm.page-cluster = 0
vm.watermark_scale_factor = 125
vm.watermark_boost_factor = 0
EOF
Settings reference: Appendix D.5.
16. Hardware Optimization
I/O scheduler configuration, SATA power management, CPU/DMA latency tuning, and audio device power rules are covered in the companion hardware optimization guide.
Reference values used on this system:
- NVMe scheduler:
kyber - SATA SSD scheduler:
mq-deadline - SATA link power:
med_power_with_dipm
17. Audio Configuration
17.1 PipeWire Services
PipeWire and its session manager run as user services:
systemctl --user enable pipewire pipewire-pulse wireplumber
17.2 Real-Time Privileges
PipeWire uses RealtimeKit (rtkit) for real-time scheduling and does not require manual group-based rtprio limits for normal operation. The following limits support direct hardware access in ALSA/OSS remote sessions and non-PipeWire audio applications:
cat > /etc/security/limits.d/20-audio.conf << 'EOF'
@audio - rtprio 99
@audio - memlock unlimited
EOF
Add the user to the audio group:
usermod -aG audio username
18. Power Management
18.1 TLP Configuration
TLP optimizes power consumption automatically. Override default behavior with a drop-in configuration:
cat > /etc/tlp.d/00-custom.conf << 'EOF'
DEVICES_TO_ENABLE_ON_STARTUP="wifi bluetooth"
USB_AUTOSUSPEND=0
EOF
DEVICES_TO_ENABLE_ON_STARTUP: forces listed devices on at startup regardless of their state at last shutdown. Remove a device from this list to preserve its last-used state across reboots.
USB_AUTOSUSPEND=0: disables USB autosuspend for all USB devices. Enable selectively if specific devices behave correctly with power saving.
19. Optional Enhancements
19.1 Btrfs Snapshots with Snapper
Install Snapper and the optional PAC hook for automatic pre/post snapshots on pacman operations:
pacman -S snapper snap-pac
Create a Snapper configuration for the root subvolume:
snapper -c root create-config /
Verify the configuration:
snapper list-configs
Enable automatic snapshot cleanup:
systemctl enable snapper-cleanup.timer
For snapshot browsing and rollback, see the Arch Wiki: Snapper.
19.2 Paccache Hook
Automatically prune the pacman cache on each transaction, retaining the three most recent versions:
pacman -S pacman-contrib
cat > /etc/pacman.d/hooks/paccache.hook << 'EOF'
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Package
Target = *
[Action]
Description = Cleaning pacman cache...
When = PostTransaction
Exec = /usr/bin/paccache -r
EOF
19.3 NT Synchronization (Wine/Proton)
ntsync provides kernel-level NT synchronization primitive emulation, significantly improving Wine and Proton performance by reducing syscall overhead for Windows synchronization objects.
echo "ntsync" > /etc/modules-load.d/ntsync.conf
Verify the module loaded after reboot:
lsmod | grep ntsync
19.4 Efivarfs Read-Only Protection (Optional)
Mounting efivarfs read-only prevents OS-level exploitation of UEFI variables (LogoFAIL and related vulnerabilities). efivarfs (/sys/firmware/efi/efivars) exposes UEFI runtime variables — boot order, Secure Boot key databases, firmware flags. This is entirely separate from the ESP filesystem (/efi): the ESP is a FAT32 partition on disk; efivarfs is a virtual filesystem exposing firmware state through the kernel.
Add to /etc/fstab:
efivarfs /sys/firmware/efi/efivars efivarfs ro,nosuid,nodev,noexec 0 0
Kernel updates do not require a remount. The sbctl pacman hook signs EFI binary files on the ESP filesystem, which is an ordinary disk write and is unaffected by efivarfs being read-only.
A temporary remount is only needed for operations that write UEFI runtime variables directly: efibootmgr (adding or modifying boot entries), sbctl enroll-keys (writing Secure Boot keys to firmware), or systemctl reboot --firmware-setup (setting the OsIndications variable).
mount -o remount,rw /sys/firmware/efi/efivars
19.5 KVM and Virtualization
KVM configuration and virtual machine setup are covered in the companion virtualization guide.
Appendices
Appendix A: Btrfs Reference
A.1 Subvolume Layout
cryptroot (LUKS)
└── Btrfs filesystem (LABEL=ROOT)
├── @ → /
├── @home → /home
├── @var → /var
└── @snapshots → /snapshots
cryptdata (LUKS)
└── Btrfs filesystem (LABEL=DATA)
└── / → /data
The flat subvolume layout places all subvolumes directly under the Btrfs root rather than nested under @. This simplifies snapshot management because rolling back @ does not affect @home or @var, and vice versa.
@var is a separate subvolume because it contains frequently-changing data (logs, databases, cache) that should not be included in system snapshots. Including /var in a snapshot and then rolling back to it can create inconsistency between the filesystem state and running service state.
@snapshots is a separate subvolume so that snapshots themselves are not included in snapshots (which would create recursive snapshot behavior).
A.2 Mount Option Inheritance
Btrfs mount options apply at the filesystem level from the first mount. compress=zstd:2 set on @ applies to all subvolumes on that device — specifying it on subsequent subvolume mounts in fstab is redundant but harmless. noatime is a VFS-level option and must be specified per-mount.
A.3 TRIM and Async Discard
Three mechanisms handle TRIM on this setup, working as a layered stack:
discard in crypttab opens the TRIM passthrough gate in dm-crypt. TRIM commands issued by the filesystem travel through the encryption layer to the physical device. Without this option, all TRIM commands are silently dropped at the dm-crypt boundary regardless of what the filesystem does.
Btrfs async discard (discard=async, kernel default since 6.2) is Btrfs's built-in mechanism. When blocks are freed, Btrfs batches them and sends TRIM commands asynchronously in the background. This avoids the write-latency penalty of synchronous discard (which would block until the SSD acknowledges each TRIM).
fstrim.timer runs fstrim weekly, requesting that the filesystem report all currently-free blocks to the device in a single pass. This catches anything async discard may have missed and handles the ESP (vfat has no async discard).
The dependency: discard in crypttab must be present for either async discard or fstrim to reach the physical device. Without it, both mechanisms generate TRIM commands that are immediately discarded by dm-crypt.
Security consideration: discard leaks information about which storage blocks contain data — an observer with physical access can determine the approximate size and location of encrypted data. For high-security deployments, remove discard from crypttab and rely on fstrim alone, or disable TRIM entirely.
Appendix B: Package Purposes
Core System
| Package | Purpose |
|---|---|
base |
Minimal base system utilities |
base-devel |
Build tools required by AUR and some packages |
linux-hardened |
Security-hardened kernel; enhanced ASLR, restrictive compile-time defaults, additional patch set. Alternative: linux-zen (performance-oriented, no hardening) |
linux-hardened-headers |
Kernel headers; required for DKMS module compilation |
linux-firmware |
Firmware blobs for hardware peripherals |
amd-ucode |
AMD CPU microcode updates loaded early by the initramfs |
sof-firmware |
Sound Open Firmware; primarily for Intel SOF-based audio hardware; harmless on AMD |
Storage and Encryption
| Package | Purpose |
|---|---|
cryptsetup |
LUKS/dm-crypt management |
btrfs-progs |
Btrfs userspace tools |
zram-generator |
Systemd-native zram device configuration |
Boot
| Package | Purpose |
|---|---|
efibootmgr |
Creates and manages UEFI boot entries |
sbctl |
Secure Boot key management and UKI signing |
tpm2-tools |
TPM 2.0 command-line utilities |
tpm2-tss |
TPM 2.0 Software Stack; required for systemd-cryptenroll TPM operations |
Networking
| Package | Purpose |
|---|---|
iwd |
Intel Wireless Daemon; Wi-Fi management with built-in MAC randomization |
systemd-resolvconf |
Provides resolvconf compatibility shim; ensures tools that write to resolv.conf work with systemd-resolved |
chrony |
NTP client/server with NTS (authenticated, encrypted time sync) support |
wireless-regdb |
Regulatory domain database for the wireless subsystem |
iptables-nft |
iptables compatibility layer over nftables backend; required by tools that use iptables directly |
nftables |
Netfilter packet filtering framework |
Security
| Package | Purpose |
|---|---|
apparmor |
Mandatory access control; profiles restrict what individual programs can access |
Graphics
| Package | Purpose |
|---|---|
mesa |
OpenGL and Vulkan stack for AMD/Intel (open-source) |
vulkan-radeon |
AMD Vulkan driver (ACO/RADV) |
libva-mesa-driver |
VA-API hardware video decoding for AMD GPUs |
Audio
| Package | Purpose |
|---|---|
pipewire |
Low-latency audio/video router and processor |
pipewire-pulse |
PulseAudio compatibility layer over PipeWire |
pipewire-alsa |
ALSA compatibility layer over PipeWire |
pipewire-jack |
JACK compatibility layer over PipeWire |
wireplumber |
PipeWire session/policy manager |
Power
| Package | Purpose |
|---|---|
tlp |
Advanced power management; optimizes CPU, PCI, SATA, and USB power states |
Portals and Integration
| Package | Purpose |
|---|---|
flatpak |
Application sandboxing and distribution |
xdg-desktop-portal |
Desktop portal interface for sandboxed app integration |
xdg-desktop-portal-gtk |
GTK backend for desktop portal |
Appendix C: Boot Configuration Reference
C.1 Kernel Command Line Parameters
| Parameter | Value | Purpose |
|---|---|---|
rd.luks.name |
UUID=name |
Maps LUKS UUID to device name in initramfs |
root |
UUID=... |
Root filesystem by UUID |
rootflags |
subvol=@ |
Btrfs subvolume to mount as root |
rw |
— | Mounts root read-write; required by the fsck hook |
lsm |
landlock,lockdown,yama,integrity,apparmor,bpf |
Loads Linux Security Modules in specified order; order matters for stacking |
lockdown |
integrity |
Activates the lockdown LSM in integrity mode — prevents userland from modifying the running kernel (loading unsigned modules, writing to /dev/mem, etc.). Not activated automatically by Secure Boot. |
amd_pstate |
active |
Enables AMD P-State driver in active mode; CPU firmware autonomously manages frequencies using EPP hints |
iommu |
pt |
IOMMU passthrough mode; devices that do not require DMA isolation bypass the IOMMU, reducing overhead without weakening isolation for devices that do |
sysrq_always_enabled |
1 |
Keeps SysRq permanently available for emergency recovery regardless of the runtime sysctl value |
zswap.enabled |
0 |
Disables zswap; prevents it competing with zram (linux-hardened may enable zswap by default via CONFIG_ZSWAP_DEFAULT_ON) |
nowatchdog |
— | Disables both the soft-lockup detector and the NMI watchdog; reduces timer interrupts |
C.2 Crypttab Options
| Option | Purpose |
|---|---|
discard |
Passes TRIM commands through dm-crypt to the physical device; required for Btrfs async discard to function through the encryption layer. Security implication: leaks which blocks contain data. |
timeout=120s |
Password entry timeout; 0 waits indefinitely |
tries=5 |
Maximum failed passphrase attempts before giving up |
password-echo=no |
Suppresses all password feedback; masked (default) echoes asterisks |
no-read-workqueue |
Bypasses dm-crypt internal read workqueue for synchronous processing; reduces latency on fast devices (requires kernel ≥ 5.9) |
no-write-workqueue |
Same as above for writes |
x-initrd.attach |
Keeps the device open during shutdown; prevents systemd from detaching the root device while still in use. Only needed on the root device. |
tpm2-device=auto |
Enables TPM 2.0 unlock; auto discovers the device automatically. Specify a path only when multiple TPMs are present. |
tpm2-measure-pcr=yes |
Extends PCR 15 with a hash of the volume key after unlock, establishing the PCR measurement used by the TPM enrollment policy |
fixate-volume-key=<hash> |
Pins the expected volume key SHA-256 hash; refuses attachment if the hash does not match, preventing volume impersonation attacks. Requires systemd ≥ 260. |
password-cache= |
Caches entered passphrases in the kernel keyring for 2.5 minutes; when multiple volumes share a passphrase, only one entry is required. Default: yes. |
Appendix D: Sysctl Reference
D.1 Security Sysctl
| Key | Value | Purpose |
|---|---|---|
kernel.kptr_restrict |
2 |
Hides kernel symbol addresses from all users including root |
kernel.perf_event_paranoid |
3 |
Disables performance events for unprivileged users |
kernel.kexec_load_disabled |
1 |
Prevents loading a new kernel via kexec (linux-hardened default) |
kernel.unprivileged_userfaultfd |
0 |
Disables userfaultfd for unprivileged users; closes a class of kernel exploit primitives (linux-hardened default) |
kernel.panic |
10 |
Reboots 10 seconds after a kernel panic |
kernel.oops_limit |
100 |
Limits kernel oops messages before rebooting |
kernel.warn_limit |
100 |
Limits kernel warning messages |
kernel.printk |
3 3 3 3 |
Suppresses kernel messages to console; kernel ring buffer still accessible via dmesg |
dev.tty.ldisc_autoload |
0 |
Prevents unprivileged loading of TTY line discipline modules |
fs.suid_dumpable |
0 |
Disables core dumps for setuid programs |
fs.protected_regular |
2 |
Prevents following hard links to regular files not owned by the follower |
fs.protected_fifos |
2 |
Prevents following hard links to FIFOs not owned by the follower |
net.ipv4.tcp_rfc1337 |
1 |
Protects against TCP time-wait assassination |
net.ipv4.conf.*.rp_filter |
1 |
Strict reverse path filtering; drops packets arriving on unexpected interfaces |
net.ipv4.conf.*.accept_redirects |
0 |
Ignores ICMP redirect messages |
net.ipv4.conf.*.secure_redirects |
0 |
Ignores ICMP redirects even from listed gateways |
net.ipv4.conf.*.send_redirects |
0 |
Does not send ICMP redirects |
net.ipv4.conf.*.accept_source_route |
0 |
Ignores source-routed packets |
net.ipv4.conf.*.log_martians |
1 |
Logs packets with impossible source addresses |
net.ipv4.icmp_echo_ignore_broadcasts |
1 |
Ignores broadcast ICMP echo requests; prevents Smurf amplification |
net.ipv4.icmp_ignore_bogus_error_responses |
1 |
Ignores malformed ICMP error responses |
net.ipv6.conf.*.accept_redirects |
0 |
Ignores ICMPv6 redirect messages |
net.ipv6.conf.*.accept_source_route |
0 |
Ignores IPv6 source-routed packets |
net.ipv6.conf.*.use_tempaddr |
2 |
Enables IPv6 privacy extensions; uses temporary addresses for outgoing connections |
net.ipv4.tcp_timestamps |
0 |
Disables TCP timestamps; prevents remote uptime fingerprinting |
D.2 Linux-Hardened Sysctl
| Key | Value | Purpose |
|---|---|---|
kernel.unprivileged_userns_clone |
1 |
Re-enables unprivileged user namespaces; required for Steam, Flatpak, bubblewrap, and browser renderer sandboxes. linux-hardened disables this by default; this key does not exist on mainline kernels. |
D.3 Settings Intentionally Not Applied
| Key | Reason |
|---|---|
kernel.kexec_load_disabled = 1 |
linux-hardened default; listed in D.1 for explicitness and portability |
kernel.unprivileged_userfaultfd = 0 |
linux-hardened default; listed in D.1 for explicitness |
net.ipv4.tcp_syncookies = 1 |
Kernel default since 5.10 |
fs.protected_hardlinks = 1 |
Kernel default |
fs.protected_symlinks = 1 |
Kernel default |
fs.binfmt_misc.status = 0 |
Breaks Wine and Proton |
net.core.default_qdisc = cake |
Resource overhead not justified for a laptop; BBR operates correctly without it |
kernel.modules_disabled = 1 |
Breaks USB devices, VMs, and all runtime module loading |
kernel.yama.ptrace_scope = 3 |
Breaks Wine, Proton, debuggers, and anti-cheat systems |
net.ipv4.icmp_echo_ignore_all |
Breaks ping diagnostics; too disruptive without security benefit |
kernel.sysrq = 0 |
Removes emergency recovery capability |
hidepid |
Explicitly unsupported with systemd; breaks D-Bus, Polkit, Bluetooth, and other inter-process communication |
D.4 Performance Sysctl
| Key | Value | Purpose |
|---|---|---|
net.ipv4.tcp_fastopen |
3 |
Enables TCP Fast Open for both client and server connections; reduces connection setup latency |
net.ipv4.tcp_mtu_probing |
1 |
Enables MTU discovery; allows larger packets when ICMP blackhole is detected |
net.ipv4.tcp_fin_timeout |
30 |
Reduces TIME_WAIT socket timeout from 60 to 30 seconds |
net.ipv4.tcp_slow_start_after_idle |
0 |
Prevents TCP slow-start after an idle period on persistent connections |
net.ipv4.tcp_congestion_control |
bbr |
Bottleneck Bandwidth and RTT congestion control; higher throughput and lower latency than CUBIC on most connections |
net.ipv4.ip_local_port_range |
30000 65535 |
Expands the ephemeral port range; beneficial for systems with many simultaneous connections |
net.core.netdev_max_backlog |
4096 |
Increases packet queue before the kernel drops packets on busy interfaces |
fs.inotify.max_user_instances |
8192 |
Increases inotify watch limit; required by development tools, file managers, and some games |
vm.compaction_proactiveness |
0 |
Disables proactive memory compaction; reduces background CPU usage on systems with sufficient RAM |
vm.min_free_kbytes |
614400 |
Increases minimum free memory reserve (~600MB); reduces allocation latency spikes |
vm.vfs_cache_pressure |
40 |
Reduces tendency to reclaim inode/dentry caches; improves filesystem performance with abundant RAM |
vm.page_lock_unfairness |
1 |
Reduces page lock contention in memory-intensive workloads |
vm.dirty_background_bytes |
268435456 |
Starts background writeback at 256MB dirty data |
vm.dirty_bytes |
536870912 |
Throttles processes at 512MB dirty data |
vm.dirty_writeback_centisecs |
1000 |
Writeback flush interval: 10 seconds |
vm.max_map_count |
2147483642 |
Maximum memory map count; required by games and some applications |
D.5 Zram Sysctl
| Key | Value | Purpose |
|---|---|---|
vm.swappiness |
180 |
Aggressively prefers zram over filesystem reclaim; values above 100 are valid for memory-compressed swap significantly faster than storage I/O |
vm.page-cluster |
0 |
Disables readahead for swap; appropriate for zram where sequential readahead has no benefit |
vm.watermark_scale_factor |
125 |
Increases the gap between low and high memory watermarks; reduces reclaim frequency |
vm.watermark_boost_factor |
0 |
Disables watermark boosting; prevents aggressive reclaim spikes after memory pressure events |