Installing Arch Linux with BTRFS and Full Disk Encryption

If you want a fast, modern, and secure Linux setup, Arch Linux with BTRFS on an encrypted disk is a great combination. BTRFS gives you snapshots, transparent compression, and copy-on-write semantics. LUKS encryption ensures your data is safe at rest. Together they make a robust foundation for a daily driver.

This guide walks through a complete installation from live ISO to a bootable, encrypted Arch system. It assumes UEFI, an SSD, and uses GRUB as the bootloader. No swap partition is needed — we’ll use a swap file instead.


Prerequisites

  • A bootable Arch Linux USB
  • An internet connection (wired or Wi-Fi)
  • A target disk (the guide uses /dev/sda — adjust to match your system)

Step 1: Boot Environment Setup

Set a Readable Font

The default console font is small. Make it easier on your eyes:

setfont ter-u20n

Verify UEFI Mode

cat /sys/firmware/efi/fw_platform_size
  • 64 → 64-bit UEFI (most common, all bootloaders supported)
  • 32 → 32-bit UEFI (limited to systemd-boot)
  • File missing → likely booted in BIOS/legacy mode

This guide assumes 64-bit UEFI.


Step 2: Network

Wi-Fi (skip if on ethernet)

iwctl --passphrase [password] station wlan0 connect [network-name]

Verify Connectivity

ping -c5 archlinux.org

Step 3: System Clock and Mirrors

Sync the Clock

timedatectl set-ntp true

Set Fast Mirrors with Reflector

reflector --country US --latest 5 --sort rate --save /etc/pacman.d/mirrorlist
pacman -Syy

Tweak pacman.conf

Enable parallel downloads and color output for a faster, prettier experience:

nano /etc/pacman.conf

Find the [options] section and set:

Color
ParallelDownloads = 5

Save with Ctrl+O, exit with Ctrl+X.


Step 4: Partition the Disk

Identify Your Disk

lsblk

Partition with cfdisk

cfdisk /dev/sda

If prompted for a label type, select gpt.

Create two partitions:

PartitionSizeTypePurpose
/dev/sda1477MEFI SystemBoot/EFI
/dev/sda2RemainingLinux filesystemEncrypted root

No swap partition is needed — a swap file on BTRFS will be used instead.

Select Write, type yes, then Quit.

Confirm the layout:

lsblk

Step 5: Encryption and Filesystem Setup

Format the EFI Partition

mkfs.fat -F32 /dev/sda1

Encrypt the Root Partition

cryptsetup --cipher=aes-xts-plain64 --hash=sha512 --use-random --verify-passphrase luksFormat /dev/sda2

You’ll be asked to confirm with YES and set a passphrase. Don’t lose this passphrase — there is no recovery.

Open the Encrypted Partition

cryptsetup luksOpen /dev/sda2 archlinux

This maps the decrypted device to /dev/mapper/archlinux.

Format as BTRFS

mkfs.btrfs /dev/mapper/archlinux

Step 6: Create BTRFS Subvolumes

BTRFS subvolumes let you take granular snapshots and exclude certain directories (like logs or cache) from rollbacks.

Mount and Create Subvolumes

mount /dev/mapper/archlinux /mnt
cd /mnt

btrfs subvolume create @
btrfs subvolume create @home
btrfs subvolume create @cache
btrfs subvolume create @images   # libvirt VM disk images — skip if you're not running VMs
btrfs subvolume create @tmp
btrfs subvolume create @log
btrfs subvolume create @snapshots

cd
umount /mnt

Mount Subvolumes with Optimized Options

The mount options used here are tuned for SSDs:

  • noatime — no access time writes, reduces wear
  • compress=zstd — transparent compression (good ratio + speed)
  • ssd — enables SSD-aware optimizations
  • discard=async — async TRIM support
mount -o noatime,space_cache=v2,compress=zstd,ssd,discard=async,subvol=@ /dev/mapper/archlinux /mnt

mkdir -p /mnt/{boot/efi,home,.snapshots,tmp,var/{cache,log,lib/libvirt/images}}

mount -o noatime,space_cache=v2,compress=zstd,ssd,discard=async,subvol=@home       /dev/mapper/archlinux /mnt/home
mount -o noatime,space_cache=v2,compress=zstd,ssd,discard=async,subvol=@snapshots  /dev/mapper/archlinux /mnt/.snapshots
mount -o noatime,space_cache=v2,compress=zstd,ssd,discard=async,subvol=@tmp        /dev/mapper/archlinux /mnt/tmp
mount -o noatime,space_cache=v2,compress=zstd,ssd,discard=async,subvol=@cache      /dev/mapper/archlinux /mnt/var/cache
mount -o noatime,space_cache=v2,compress=zstd,ssd,discard=async,subvol=@log        /dev/mapper/archlinux /mnt/var/log
mount -o noatime,space_cache=v2,compress=zstd,ssd,discard=async,subvol=@images     /dev/mapper/archlinux /mnt/var/lib/libvirt/images

mount /dev/sda1 /mnt/boot/efi

Step 7: Install the Base System

pacstrap -K /mnt base base-devel linux linux-firmware git vim openssh amd-ucode reflector

Swap amd-ucode for intel-ucode if you’re on Intel hardware.


Step 8: Generate fstab

genfstab -U /mnt >> /mnt/etc/fstab

Review the output to confirm all subvolumes and the EFI partition are listed:

cat /mnt/etc/fstab

Step 9: Chroot into the New System

arch-chroot /mnt

Everything from here runs inside your new installation.


Step 10: Configure the Initramfs

The initramfs needs to know about BTRFS and LUKS so it can unlock the disk at boot.

vim /etc/mkinitcpio.conf

Edit the following lines:

MODULES=(btrfs)

HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block encrypt filesystems fsck)

Key hooks:

  • encrypt — prompts for the LUKS passphrase at boot
  • btrfs in MODULES — ensures BTRFS is available in the initramfs

Rebuild the initramfs:

mkinitcpio -p linux

Step 11: Localization and Time

Timezone

ln -sf /usr/share/zoneinfo/America/Chicago /etc/localtime
hwclock --systohc --utc

Adjust the timezone path to match your region.

Locale

vim /etc/locale.gen

Uncomment en_US.UTF-8 UTF-8, then generate:

locale-gen
echo LANG=en_US.UTF-8 > /etc/locale.conf

Step 12: Hostname and Hosts File

echo arch-base-grub > /etc/hostname
vim /etc/hosts

Add:

127.0.0.1       localhost
::1             localhost
127.0.1.1       arch-base-grub.localdomain arch-base-grub

Step 13: Set Root Password

passwd

Step 14: pacman Configuration

vim /etc/pacman.conf

In the [options] section:

Color
CheckSpace
VerbosePkgLists
ParallelDownloads = 5
ILoveCandy

Also uncomment the [multilib] section and its Include line to enable 32-bit package support (needed for Steam, Wine, etc.).


Step 15: Install Additional Packages

This installs everything needed for a full desktop-ready system including audio, networking, Bluetooth, printing, GPU drivers, virtualization, and more:

pacman -S grub efibootmgr grub-btrfs networkmanager network-manager-applet dialog \
  wpa_supplicant linux-headers alsa-utils pipewire pipewire-alsa pipewire-pulse pipewire-jack \
  bash-completion zsh zsh-completions firewalld terminus-font cups btrfs-progs \
  xf86-video-amdgpu xf86-video-nouveau mesa lib32-mesa vulkan-radeon lib32-vulkan-radeon \
  libva-mesa-driver lib32-libva-mesa-driver mesa-vdpau lib32-mesa-vdpau \
  os-prober mtools dosfstools avahi xdg-user-dirs xdg-utils gvfs gvfs-smb nfs-utils \
  inetutils dnsutils bluez dnsmasq openbsd-netcat ipset nss-mdns acpid ntfs-3g \
  pacman-contrib zip unzip fastfetch duf haveged exfatprogs \
  qemu virt-manager virt-viewer edk2-ovmf bridge-utils vde2 iptables-nft ebtables libguestfs

Tailor this list to your needs. The GPU drivers here cover AMD and Nouveau (NVIDIA open). Remove what you don’t need.


Step 16: Install and Configure GRUB

First, edit /etc/default/grub to pass the encrypted partition UUID and the BTRFS root subvolume to the kernel. This must happen before generating the GRUB config:

vim /etc/default/grub

Set the following line:

GRUB_CMDLINE_LINUX="cryptdevice=UUID=$(blkid -s UUID -o value /dev/sda2):archlinux root=/dev/mapper/archlinux rootflags=subvol=@"
  • cryptdevice — tells GRUB which partition to unlock and what name to give the mapped device
  • root — points to the decrypted device
  • rootflags=subvol=@ — tells BTRFS to mount the @ subvolume as root; without this, the initramfs mounts the top-level BTRFS volume and the system won’t boot correctly

Then install GRUB and generate the config:

grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ArchLinux
grub-mkconfig -o /boot/grub/grub.cfg

Step 17: Enable System Services

systemctl enable NetworkManager
systemctl enable bluetooth
systemctl enable sshd
systemctl enable reflector.timer
systemctl enable avahi-daemon
systemctl enable firewalld.service
systemctl enable cups.service
systemctl enable fstrim.timer
systemctl enable acpid

fstrim.timer runs periodic TRIM on your SSD — important for long-term performance.


Step 18: Create a User

Add the libvirt Group (for VM management)

groupadd --system libvirt

Create Your User

useradd -m -G sys,log,network,floppy,scanner,power,rfkill,users,video,storage,optical,lp,audio,wheel,adm,libvirt -s /bin/zsh yourusername
passwd yourusername

Grant sudo Access

export VISUAL=vim
visudo /etc/sudoers

Uncomment the line that allows wheel group members to use sudo:

%wheel ALL=(ALL:ALL) ALL

Step 19: Reboot

Exit the chroot and unmount everything:

exit
umount -R /mnt
reboot

Remove the USB drive when the system powers down. On the next boot, GRUB will appear, then prompt you for your LUKS passphrase to unlock the disk.


What You Get

After a successful boot you’ll have:

  • Full disk encryption via LUKS2 — data is protected at rest
  • BTRFS with subvolumes for clean snapshot boundaries
  • zstd compression — transparent, fast compression saving disk space
  • SSD-optimized mount options and async TRIM
  • Pipewire for modern audio
  • NetworkManager for easy network management
  • Firewalld for a default-deny firewall
  • KVM/QEMU virtualization stack ready to go

From here you can install a desktop environment, configure your shell, and set up snapper or Timeshift for automated BTRFS snapshots.


Based on a personal installation walkthrough. Tested on hardware with AMD GPU and NVMe SSD.

Leave a Reply

Your email address will not be published. Required fields are marked *