This is a worked example for installing Arch Linux on a UEFI system with an LVM volume group inside a LUKS-encrypted root partition. The EFI System Partition (/efi) remains unencrypted; /boot is a directory on the encrypted root filesystem, not a separate encrypted partition. These commands erase or repartition disks and need to be adapted to the target machine.
For current installation and security guidance, start with the Arch Linux Installation Guide and the dm-crypt encryption guide. An unencrypted EFI System Partition does not protect boot files from offline modification. Consult the Secure Boot guide if that threat matters.
The workstations run CachyOS, which builds on Arch and adds CPU-optimized repositories, its own kernels and cachyos-settings. You can install it with the CachyOS installer and go straight to Dotfiles, or follow this guide and then add the CachyOS repositories. In both cases, read the CachyOS post-install setup.
This page retains a GRUB-based example. Huntrar's current guide now uses systemd-boot and unified kernel images; follow the ArchWiki for bootloader-specific details.
Note: The device examples use /dev/nvme0n1. Replace the disk and partition paths, partition sizes, and logical volume sizes to match your hardware.
Arch Linux changes frequently. Check package names and commands against the official wiki before using this machine-specific example. You can also use archinstall and follow the dotfiles setup section below.
Download the ISO and its detached signature from the official Arch Linux downloads page. Verify the signature before writing the image. Replace the date below with the filename you downloaded.
gpg --auto-key-locate clear,wkd --locate-external-key [email protected]
gpg --fingerprint [email protected]
gpg --verify archlinux-YYYY.MM.DD-x86_64.iso.sig archlinux-YYYY.MM.DD-x86_64.isoCompare the displayed fingerprint with the one on the downloads page before accepting the signature.
Identify the USB device with lsblk and verify its model and size. Writing the image erases the selected device. Use the whole device, not a partition. Find its stable path with ls -l /dev/disk/by-id/usb-* and replace the example only after checking it:
lsblk -o NAME,PATH,SIZE,MODEL,TRAN
sudo dd bs=4M if=archlinux-YYYY.MM.DD-x86_64.iso of=/dev/disk/by-id/usb-REPLACE_ME conv=fsync status=progressCheck that the machine booted in UEFI mode, that the network works and that the clock is synchronized:
cat /sys/firmware/efi/fw_platform_size # 64 on a 64-bit UEFI; missing in BIOS mode
ping -c 3 archlinux.org
timedatectlThe example creates a 1 MiB BIOS boot partition, a 1 GiB EFI System Partition, and one LUKS partition using the remaining space. The BIOS boot partition is not needed for UEFI-only systems; omit it only if you also update the partition numbers used below.
Check the target disk with lsblk before starting. The o command below replaces its partition table.
gdisk /dev/nvme0n1
o
n
[Enter]
0
+1M
ef02
n
[Enter]
[Enter]
+1G
ef00
n
[Enter]
[Enter]
[Enter]
8309
wcryptsetup luksFormat --type luks2 /dev/nvme0n1p3
cryptsetup luksOpen /dev/nvme0n1p3 cryptlvmBefore relying on GRUB to unlock the encrypted /boot, check that the installed GRUB version supports the LUKS2 key-derivation function in use. See the ArchWiki GRUB guidance. Keep the default key-derivation settings unless the bootloader requires a compatible alternative. A LUKS header backup can recover from header damage, but it also lets someone attempt offline passphrase guesses. Protect it, store it separately from the encrypted disk, and do not rely on it to recover a forgotten passphrase.
cryptsetup luksHeaderBackup /dev/nvme0n1p3 \
--header-backup-file /path/on/offline-storage/cryptlvm-header.imgdm-crypt drops discard requests by default, so the weekly fstrim.timer that Ansible enables does nothing on the encrypted volumes. To allow discards, store the flag in the LUKS2 header once the system is installed, then reboot:
cryptsetup --allow-discards --persistent refresh cryptlvm
lsblk --discard # DISC-GRAN and DISC-MAX must not be 0 for cryptlvmDiscards show which blocks are free, which leaks the rough amount of data and the filesystem type. See the ArchWiki dm-crypt TRIM notes.
RAM_SIZE=$(($(getconf _PHYS_PAGES) * $(getconf PAGE_SIZE) / (1024 * 1024)))
pvcreate /dev/mapper/cryptlvm
vgcreate archlvm /dev/mapper/cryptlvm
lvcreate -L 32G archlvm -n slash
lvcreate -L 30G archlvm -n opt
lvcreate -L 10G archlvm -n var_lib_docker
lvcreate -L "${RAM_SIZE}M" archlvm -n swap
lvcreate -l 100%FREE archlvm -n homeThe swap volume matches the RAM size so the machine can hibernate. Without hibernation you can drop it: cachyos-settings sets up swap on zram, and zram-generator does the same on plain Arch.
mkfs.fat -F32 /dev/nvme0n1p2 -n EFI
mkfs.ext4 /dev/mapper/archlvm-slash -L slash
mkfs.ext4 /dev/mapper/archlvm-home -L home
mkfs.ext4 /dev/mapper/archlvm-opt -L opt
mkfs.ext4 /dev/mapper/archlvm-var_lib_docker -L var_lib_docker
mkswap /dev/mapper/archlvm-swap -L swap
swapon /dev/mapper/archlvm-swapmount /dev/mapper/archlvm-slash /mnt
mkdir /mnt/efi /mnt/home /mnt/var/lib/docker /mnt/opt -p
mount /dev/nvme0n1p2 /mnt/efi
mount /dev/mapper/archlvm-home /mnt/home
mount /dev/mapper/archlvm-var_lib_docker /mnt/var/lib/docker
mount /dev/mapper/archlvm-opt /mnt/opt# Available kernel options:
# KERNEL='linux' # Vanilla Linux kernel and modules, with a few patches applied.
# KERNEL='linux-lts' # Long-term support (LTS) Linux kernel and modules.
# KERNEL='linux-zen' # Result of a collaborative effort of kernel hackers to provide the best Linux kernel possible for everyday systems.
# KERNEL='linux-hardened' # Security-focused kernel with additional hardening features
KERNEL='linux'
# Available microcode options:
# UCODE='intel-ucode' # for Intel processors.
# UCODE='amd-ucode' # for AMD processors.
UCODE='intel-ucode' # for Intel processors, adjust as needed
pacstrap -K /mnt \
base \
base-devel \
ansible \
cryptsetup \
${KERNEL} \
${KERNEL}-headers \
${UCODE} \
wireless-regdb \
efibootmgr \
git \
grub \
linux-firmware \
lvm2 \
fastfetch \
network-manager-applet \
networkmanager \
openssh \
os-prober \
python \
systemd-resolvconf \
rsync \
sudo \
terminus-font \
vim \
wpa_supplicant \
zshAdd sof-firmware on laptops whose built-in audio needs Sound Open Firmware, which covers most recent Intel laptops. os-prober is only needed when another operating system shares the machine.
systemd-resolved is the only resolver. Point /etc/resolv.conf at its stub from outside the chroot, because arch-chroot bind-mounts that file. The Ansible dns tag then configures resolved and NetworkManager.
ln -sf ../run/systemd/resolve/stub-resolv.conf /mnt/etc/resolv.confHosts installed with the earlier openresolv instructions are migrated by the same tag; follow the DNS migration note.
Ansible sets the Wi-Fi regulatory domain (wireless_regdom tag, wireless_regdom_country: FR in group_vars/all/main.yml) and, on a portable machine, the Intel Wi-Fi and HDA audio power-saving module options (power_save tag). Nothing is needed here.
genfstab -U /mnt >> /mnt/etc/fstabDo not add a /tmp line: systemd's tmp.mount already mounts /tmp as a tmpfs with nosuid,nodev.
arch-chroot /mntCheck the resulting layout with lsblk. Device names and sizes will vary; this output illustrates the example commands above.
| NAME | MAJ:MIN | RM | SIZE | RO | TYPE | MOUNTPOINT |
|---|---|---|---|---|---|---|
| nvme0n1 | 259:0 | 0 | 953.9G | 0 | disk | |
| ├─nvme0n1p1 | 259:1 | 0 | 1M | 0 | part | |
| ├─nvme0n1p2 | 259:2 | 0 | 1G | 0 | part | /efi |
| ├─nvme0n1p3 | 259:3 | 0 | 953.3G | 0 | part | |
| ..└─cryptlvm | 254:0 | 0 | 953.3G | 0 | crypt | |
| ....├─archlvm-swap | 254:1 | 0 | 31.1G | 0 | lvm | [SWAP] |
| ....├─archlvm-slash | 254:2 | 0 | 32G | 0 | lvm | / |
| ....└─archlvm-home | 254:3 | 0 | 850G | 0 | lvm | /home |
| ....└─archlvm-opt | 254:4 | 0 | 30G | 0 | lvm | /opt |
| ....└─archlvm-var_lib_docker | 254:5 | 0 | 10G | 0 | lvm | /var/lib/docker |
Leave /etc/makepkg.conf alone. The Ansible makepkg tag writes its overrides to /etc/makepkg.conf.d/zz-dotfiles.conf: -march=native -mtune=native, half the CPU cores for MAKEFLAGS, and no debug packages. These settings only affect packages built on this machine, such as AUR packages. A package built this way may not run on a different CPU, so do not copy it to another computer.
# Replace Region/City with your time zone.
ln -sf /usr/share/zoneinfo/Region/City /etc/localtime
hwclock --systohcsed -i 's/^#\(fr_FR.UTF-8 UTF-8\)/\1/' /etc/locale.gen
sed -i 's/^#\(en_US.UTF-8 UTF-8\)/\1/' /etc/locale.gen
locale-gen
echo 'LANG=en_US.UTF-8' > /etc/locale.confecho 'KEYMAP=us-acentos' > /etc/vconsole.conf
echo 'FONT=ter-116n' >> /etc/vconsole.confThe sd-vconsole initramfs hook reads this file, so the LUKS passphrase prompt uses this keymap. Hyprland sets its own keyboard layout in the dotfiles, and Xwayland applications use it, so no Xorg keyboard file is needed.
myhostname='MyArch'
echo "${myhostname}" > /etc/hostnameLeave /etc/hosts as installed: systemd's nss-myhostname resolves the host name and localhost.
UUID=$(blkid /dev/nvme0n1p3 -s UUID -o value)
sed -i "/^GRUB_CMDLINE_LINUX=/cGRUB_CMDLINE_LINUX=\"rd.luks.name=${UUID}=cryptlvm root=/dev/mapper/archlvm-slash\"" /etc/default/grub
sed -i "/GRUB_ENABLE_CRYPTODISK=/cGRUB_ENABLE_CRYPTODISK=y" /etc/default/grub
grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=ArchLinux
grub-mkconfig -o /boot/grub/grub.cfgmkdir -p /etc/cryptsetup-keys.d
head -c 64 /dev/urandom > /etc/cryptsetup-keys.d/cryptlvm.key
chmod 600 /etc/cryptsetup-keys.d/cryptlvm.key
cryptsetup -v luksAddKey /dev/nvme0n1p3 /etc/cryptsetup-keys.d/cryptlvm.key
# The key is embedded in the initramfs. Protect the boot chain and keep a
# separate recovery method; the EFI System Partition remains unencrypted.
sed -i '/^FILES/c\FILES=(/etc/cryptsetup-keys.d/cryptlvm.key)' /etc/mkinitcpio.conf
sed -i '/^HOOKS/c\HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt lvm2 filesystems fsck)' /etc/mkinitcpio.conf
mkinitcpio -PThe sd-encrypt hook uses /etc/cryptsetup-keys.d/cryptlvm.key for the cryptlvm mapping. See the ArchWiki's mkinitcpio encryption instructions.
systemctl enable NetworkManager
systemctl enable systemd-resolvedThe Ansible time_sync tag enables systemd-timesyncd later, unless another NTP client such as chrony is in use.
MYUSER='MyUser'
useradd -m -s /bin/zsh -G wheel "${MYUSER}"
EDITOR=vi visudo -f /etc/sudoers.d/wheel
passwd "${MYUSER}"In visudo, add %wheel ALL=(ALL:ALL) ALL to require the user's password for administrative commands. Do not edit sudoers files with a plain text editor. Once sudo works for this user, you can lock the root account with passwd -l root. Otherwise, set a root password with passwd.
Leave /etc/pacman.conf alone. The Ansible installer enables Color, CheckSpace, and multilib in it, and sets ParallelDownloads = 5. When it enables multilib, it runs pacman -Syu, which syncs package databases and upgrades installed packages. Run pacman -Syu separately when you want a full system upgrade and multilib is already enabled. The base and Steam groups include lib32-* packages from multilib.
Skip this on a system installed with the CachyOS installer. On Arch, the CachyOS script detects the CPU level, backs up /etc/pacman.conf and adds the matching repositories above the Arch ones:
curl -O https://mirror.cachyos.org/cachyos-repo.tar.xz
tar xvf cachyos-repo.tar.xz && cd cachyos-repo
sudo ./cachyos-repo.shsudo ./cachyos-repo.sh --remove undoes it. Check the CPU level with /lib/ld-linux-x86-64.so.2 --help | grep supported. Intel 12th generation and later CPUs may list x86-64-v4, but AVX-512 is disabled on them, so use v3. The [cachyos] repository replaces pacman with the CachyOS build. See CachyOS optimized repositories.
CachyOS ranks its mirrors with cachyos-rate-mirrors.timer. Do not also enable reflector.timer, because both rewrite the mirror lists.
# Run setup commands in the regular user's context.
sudo -u "${MYUSER}" -i bash -c '
git clone https://gitlab.com/pad92/dotfiles.git ~/.dotfiles
mkdir -p ~/.config
'The installer uses yay when it is installed. If selected AUR packages need it and it is missing, the installer builds yay from the AUR as the regular user, then installs it. Set -e packages_aur_action=ask to confirm the helper build and AUR package installation, or -e packages_aur_action=skip to skip AUR packages. Review AUR build files before installing them. See the ArchWiki AUR guidance for the security model and recommended workflow.
Install the dotfiles and selected package groups as the regular user. The read-only package plan is optional. Avoid passing every package list to an AUR helper: the lists contain optional and hardware-specific groups that should not all be installed together.
sudo -u "${MYUSER}" -i bash -c 'cd ~/.dotfiles && make check'
sudo -u "${MYUSER}" -i bash -c 'cd ~/.dotfiles && make deploy'exitsync
umount -R /mnt
rebootsudo systemctl enable --now auto-cpufreqauto-cpufreq conflicts with power-profiles-daemon. With the 21_steam group, the gaming tag offers to remove it (gaming_power_manager_conflict_action).
The CachyOS installer enables ufw, which denies incoming and allows outgoing connections. A system installed from this guide has no firewall, and Ansible does not configure one. See the ArchWiki security guide and the CachyOS post-install setup.
The package_services tag enables fstrim.timer with the 01_base group.
The package_services tag also enables paccache.timer with the 01_base group. It keeps the last three versions of each package in the pacman cache.
yay -S usbguard usbguard-applet-qt
sudo usbguard generate-policy | sudo tee /etc/usbguard/rules.conf
sudo systemctl start usbguard.service
sudo systemctl enable usbguard.serviceSelect the Docker package group in the dotfiles installer. For access to the Docker daemon without sudo, follow the Docker post-install guidance and consider the security implications of membership in the docker group.
Select the matching NVIDIA driver group in the dotfiles installer. It separates legacy and modern hardware; avoid mixing both groups. Ansible manages the NVIDIA module options and regenerates the initramfs when its configuration changes. It detects mkinitcpio or dracut; if both or neither are installed, set system_initramfs_generator to the one in use. For manual driver changes, follow the driver's initramfs instructions.
The NVIDIA package groups include nvidia-prime. Select the driver group that matches the GPU rather than installing a second driver set manually.
The gnome_keyring tag adds the pam_gnome_keyring.so auth, session and password rules to /etc/pam.d/login, for TTY logins. Automatic unlock requires the login password and the keyring password to match. Display managers may already configure PAM; set gnome_keyring_pam_enabled: false and use their PAM file instead. See the ArchWiki GNOME Keyring guide for other login methods.
For complete documentation, see Hyprland Wiki.
UWSM (Universal Wayland Session Manager) runs the compositor in systemd units and manages the session environment and applications.
The 01_base package group installs uwsm and libnewt, which provides the whiptail menu that uwsm select shows.
This dotfiles setup installs the following logic in ~/.zprofile, so it runs only for a login shell attached to a terminal:
if [[ -o login && -t 0 ]] && command -v uwsm >/dev/null 2>&1; then
if uwsm check may-start && uwsm select; then
exec uwsm start default
fi
fiif [[ -o login && -t 0 ]] && command -v uwsm >/dev/null 2>&1; then
if uwsm check may-start; then
exec uwsm start hyprland.desktop
fi
fiNote: For display managers, select Hyprland (uwsm-managed).
Launch graphical applications as Systemd scopes:
uwsm app -- alacrittysystemctl --user enable <service>
# If the service lacks an [Install] section:
systemctl --user add-wants graphical-session.target <service>The realtime-privileges package sets PAM limits and creates a realtime group for real-time scheduling. This can help prevent audio dropouts under high CPU load. It is part of the 01_base group, and the package_services tag adds the regular user to realtime. Log out and back in, or reboot, for the new group membership to take effect.
Security settings depend on how the machine is used and who can access it. Consult the ArchWiki security recommendations for current guidance on networking, remote access, updates, Secure Boot, and backups. Keep an independently stored backup of the LUKS header and recovery material; do not store the only copy on the encrypted disk.