Arch Linux Installation guide by
kuramion 2025-05-15.
Below is how I install Arch following the Arch's installation guide and the choices I do when installing a minimal Arch environment with:
- Encrypted root partiiton with BTRFS + subvolumes.
- Encrypted SWAP partition.
- Hibernation enabled thanks to SWAP.
- ZRAM enabled.
- Snapshots with snapper.
- Yay AUR Helper
- DE or WM of your choice! (Hyprland, KDE Plasma, Cosmic)
If you want a quick guide with only the commands straight to the installation, you can visit my Quick Install guide (Not available yet)
Go to Arch Linux downloads page, select a mirror, and download the ISO file. archlinux-RELEASE_VERSION-x86_64.iso
Prepare a USB flash drive as an installer using one of these three methods:
a) Method #1: Ventoy (Windows and Linux)
I use Ventoy to create a multiboot installer. Simply copy archlinux-RELEASE_VERSION-x86_64.iso to the USB drive, reboot, and the auto-generated menu lists all the disk images available to boot. How to install Ventoy
b) Method #2: dd (Linux)
Write the installer to an unmounted USB drive using the dd command as root.
BE VERY CAREFUL TO NOTE THE PROPER DEVICE. ALL DATA ON THE DEVICE WILL BE OVERWRITTEN.
Example: Under Linux, if a USB drive appears as sdx1, then write the installer to sdx (remove partition number) ...
sudo dd if=archlinux-RELEASE_VERSION-x86_64.iso of=/dev/sdx bs=4M status=progress oflag=syncc) Method #3: Rufus (Windows)
Download Rufus. Open the .exe and select your USB drive, then select the archlinux-RELEASE_VERSION-x86_64.iso and click start.
- In the "Boot selection" section, click the "Select" button and navigate to the location where was downloaded
archlinux-RELEASE_VERSION-x86_64.iso
- Click the "Start" button to begin the creation of the bootable USB drive with our Arch ISO. Rufus will warn about all the data on the USB will be destroyed, confirm to proceed.
Insert USB installer containing our Arch ISO into target device and boot. Installer auto-logins as root. You can also see This section. of the official arch wiki.
If UEFI mode is enabled on a UEFI motherboard, the installer will boot Arch accordingly.
Verify system is booted via UEFI by listing contents of efivars
ls /sys/firmware/efi/efivarsIf the directory don't exist, the system is booted in BIOS mode.
Note: Some of the instructions below - drive partitioning and GRUB setup in particular - will need to be modified if using BIOS mode.
Default console keymap is
us.
Optional: List available layouts ...
localectl list-keymapsOptional: You can filter the layouts with grep (example: Filter usbased keyboards) ...
localectl list-keymaps | grep usI have a latinoamerican keyboard, so, in my case I should use ...
loadkeys la-latin1Optional: Default font in the installer is very small on high resolution displays. Alternative fonts are available in /usr/share/kbd/consolefonts. You can list them with:
ls /usr/share/kbd/consolefontsSwitch to a larger font size (example: terminus ter-v24n) ...
setfont ter-v24nConnect to WiFi using iwctl utility ...
iwctl # Start iwctl utility
station wlan0 get-networks # Get SSID of nearby WiFi Networks
station wlan0 connect <Name of WiFi access point> # Connect to your WiFI
exit # Exit from iwctl utilityCheck your internet connection ...
ping -c4 archlinux.org Create a password for the live environment ...
Don't worry here, you can use a weak password because this will be only used for ssh the live enviroment.
passwd rootStart SSH service and check your local IP address of your computer ...
systemctl start sshd.service #Start SSH service
ip addr show # Search for something like '192.168.x.x'Then, on the other machine ...
ssh [email protected] # Replace 192.168.x.x with your local IP address.Enter you previously created password and that's all, you can do the installation remotely.
timedatectl set-ntp true # For sync the time
timedatectl status # Check if the system time is correct.Identify the internal storage device where Arch Linux will be installed by running lsblk, the output will be something like this:
root@archiso ~ # lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 942.7M 1 loop /run/archiso/airootfs
sda 8:0 1 28.9G 0 disk
├─sda1 8:1 1 28.8G 0 part
│ └─ventoy 253:0 0 1.3G 1 dm
└─sda2 8:2 1 32M 0 part
nvme0n1 259:0 0 953.9G 0 disk
├─nvme0n1p1 259:1 0 1G 0 part
├─nvme0n1p2 259:2 0 2G 0 part
└─nvme0n1p3 259:3 0 950.9G 0 part External disks are mostly
sdb, but in my case the live USB formatted with ventoy containing the Arch ISO issda. BE CAREFUL, you may have other drives too where you store other data, don't select the wrong drive because will be wiped, and ALL the data there will be lost.
Example: In my case my target disk for the installation is identified as nvme0n1 where we'll install Arch Linux. Replace it with your target disk.
wipefs -af /dev/nvme0n1
sgdisk --zap-all --clear /dev/nvme0n1
partprobe /dev/nvme0n1We will use gdisk for this purpose.
Note: We will have two partitions [BOOT] and [ROOT], the encrypted partiton will be [ROOT], and [BOOT] unenencrypted for the bootloader (GRUB) could access to it.
root@archiso ~ # gdisk /dev/nvme0n1p1
GPT fdisk (gdisk) version 1.0.10
Partition table scan:
MBR: protective
BSD: not present
APM: not present
GPT: present
Found valid GPT with protective MBR; using GPT.
_[create partition 1: BOOT]_
Command (? for help): n
Partition number (1-128, default 1): Enter ↵
First sector (34-2000409230, default = 2048) or {+-}size{KMGTP}: Enter ↵
Last sector (2048-2000409230, default = 2000408575) or {+-}size{KMGTP}: 1G
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): ef00
Changed type of partition to 'EFI system partition'
_[create partition 4: ROOT]_
Command (? for help): n
Partition number (4-128, default 4): Enter ↵
First sector (34-976773134, default = 9439232) or {+-}size{KMGTP}: Enter ↵
Last sector (9439232-976773134, default = 976773119) or {+-}size{KMGTP}: Enter ↵
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 8300
Changed type of partition to 'Linux filesystem'
_[Write the changes]_
Command (? for help): w
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/nvme0n1.
The operation has completed successfully.Use lsblk again for see the partitions that we've created ...
root@archiso ~ # lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 942.7M 1 loop /run/archiso/airootfs
sda 8:0 1 28.9G 0 disk
├─sda1 8:1 1 28.8G 0 part
│ └─ventoy 253:0 0 1.3G 1 dm
└─sda2 8:2 1 32M 0 part
nvme0n1 259:0 0 953.9G 0 disk
├─nvme0n1p1 259:3 0 1023M 0 part
└─nvme0n1p2 259:4 0 952.9G 0 part Format the [BOOT] partition ...
mkfs.fat -F32 /dev/nvme0n1p1Format the [ROOT] partition with LUKS encryption ...
cryptsetup luksFormat --type luks2 /dev/nvme0n1p2
# You will now be prompted for a password...Open the encrypted [ROOT] partition ...
You can change the label
cryptrootwith whatever you want, but make sure that you'll replace all the commands containing that label with your desired name.
cryptsetup luksOpen /dev/nvme0n1p2 cryptroot
# You will need to enter the password that you typed beforeFormat and mount the [ROOT] partition ...
mkfs.btrfs -f /dev/mapper/cryptroot
mount /dev/mapper/cryptroot /mntWe will create additional subvolumes for more control over rolling back the system to a previous state, while preserving the current state of other directories. These subvolumes will be excluded from any root subvolume snapshots:
Subvolume -- Mountpoint
@--/(root directory)@cache--/var/cache@home--/home(preserve user data)@snapshots--/.snapshots(is where the snapshots will be stored)@log--/var/log(excluding log files makes troubleshooting easier after reverting/)@var_tmp--/var/tmp(prevents transient files from bloating your snapshots over time)@tmp--/tmp(prevents transient files from bloating your snapshots over time)@images--/var/lib/libvirt(Virtual machine images QEMU KVM)@docker--/var/lib/docker(Docker volumes)
For create them ...
btrfs su cr /mnt/@
btrfs su cr /mnt/@cache
btrfs su cr /mnt/@home
btrfs su cr /mnt/@snapshots
btrfs su cr /mnt/@logs
btrfs su cr /mnt/@var_tmp
btrfs su cr /mnt/@tmp
btrfs su cr /mnt/@images
btrfs su cr /mnt/@docker
umount /mnt# Mount root
mount -o compress=zstd:1,noatime,subvol=@ /dev/mapper/cryptroot /mnt
# Create directories
mkdir -p /mnt/{boot/efi,home,.snapshots,tmp,var/{cache,log,tmp,lib/{libvirt,docker}}}
# Mount /var/cache
mount -o compress=zstd:1,noatime,subvol=@cache /dev/mapper/cryptroot /mnt/var/cache
# Mount /home
mount -o compress=zstd:1,noatime,subvol=@home /dev/mapper/cryptroot /mnt/home
# Mount ./snapshots
mount -o compress=zstd:1,noatime,subvol=@snapshots /dev/mapper/cryptroot /mnt/.snapshots
# Mount /var/log
mount -o compress=zstd:1,noatime,subvol=@logs /dev/mapper/cryptroot /mnt/var/log
# Mount /var/tmp
mount -o compress=zstd:1,noatime,subvol=@var_tmp /dev/mapper/cryptroot /mnt/var/tmp
# Mount /tmp
mount -o compress=zstd:1,noatime,subvol=@tmp /dev/mapper/cryptroot /mnt/tmp
# Mount /var/lib/libvirt
mount -o compress=zstd:1,noatime,subvol=@images /dev/mapper/cryptroot /mnt/var/lib/libvirt
# Mount /var/lib/docker
mount -o compress=zstd:1,noatime,subvol=@docker /dev/mapper/cryptroot /mnt/var/lib/dockerMount [BOOT] partition ...
# Create directory for ESP
mkdir /mnt/boot
# Mount ESP partition
mount /dev/nvme0n1p1 /mnt/bootVerify if all the driver are correctly mounted ...
root@archiso ~ # lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 942.7M 1 loop
sda 8:0 1 28.9G 0 disk
├─sda1 8:1 1 28.8G 0 part
│ └─ventoy 253:0 0 1.3G 1 dm
└─sda2 8:2 1 32M 0 part
nvme0n1 259:0 0 953.9G 0 disk
├─nvme0n1p1 259:3 0 1023M 0 part /mnt/boot
└─nvme0n1p2 259:4 0 952.9G 0 part
└─cryptroot 253:1 0 952.9G 0 crypt /mnt/var/lib/docker
/mnt/var/lib/libvirt
/mnt/tmp
/mnt/var/tmp
/mnt/var/log
/mnt/.snapshots
/mnt/home
/mnt/var/cache
/mntSelect an appropriate microcode package to load updates and security fixes from processor vendors.
View cpuinfo ...
grep vendor_id /proc/cpuinfoDepending on the processor, set microcode for Intel ...
export microcode="intel-ucode"Or for AMD ...
export microcode="amd-ucode"Then, Install the base system ...
pacstrap -K /mnt base base-devel linux linux-firmware linux-headers ${microcode} btrfs-progs efibootmgr lvm2 cryptsetup neovim openssh reflector ${microcode} man-db mlocate networkmanager pacman-contrib sudo pkgfile micro zsh grub grub-btrfs kbd git wgetgenfstab -U /mnt >> /mnt/etc/fstab
cat /mnt/etc/fstabWe need to chroot on to the system ...
arch-chroot /mntFormat the SWAP Partition with LUKS:
cryptsetup luksFormat --type luks2 /dev/nvme0n1p2Create the directory for store the key
mkdir -p /etc/keysGenerate the key ...
dd if=/dev/random of=/etc/keys/swap.key bs=1 count=4096 status=progress
Restrict permissions ...
chmod 600 /etc/keys/swap.keyAdding the key to the SWAP partition ...
cryptsetup luksAddKey /dev/nvme0n1p2 /etc/keys/swap.keyOpen the encrypted SWAP partition with the added key:
cryptsetup open --key-file=/etc/keys/swap.key /dev/sda3 cryptswapFormat the encrypted partition:
mkswap -L cryptswap /dev/mapper/cryptswapAdd this line to /etc/crypttab to ensure SWAP is decrypted at boot ...
Just use
swapparameter, LUKS2 automatically uses optimal parameters.
$ micro /etc/crypttab
# Line to add
cryptswap /dev/sda3 /etc/keys/swap.key swapEdit /etc/fstab and add the encrypted SWAP partition to be mounted automatically after unlock.
/dev/mapper/cryptswap swap defaults 0 0Turn on SWAP
swapon /dev/mapper/cryptswapSet desired timezone (example: my timezone is America/Lima) and update the system clock ...
ln -sf /usr/share/zoneinfo/America/Lima /etc/localtime
hwclock --systohcVerify if the hour and date is displayed correctly, if not, you selected a wrong timezone ...
dateGenerate a new mirror selection using reflector.
Example: Verbosely select the 12 most recently synchronized HTTPS mirrors, sort them by download speed, and overwrite mirrorlist ...
sudo reflector --latest 12 --protocol https --sort rate --save /etc/pacman.d/mirrorlist --verboseThen do ...
pacman -SyyRun the following commands for install yay ...
cd ~
git clone https://aur.archlinux.org/yay.git`
cd yay
makepkg -siEnable multilib repository on pacman ...
sudo micro /etc/pacman.confUncomment the following lines by removing the # -character at the start them ...
[multilib]
Include = /etc/pacman.d/mirrorlistSave the file with CTRL+S and close micro with CTRL+Q
The majority of this packages are required for have a full-working system. (example: networkmanager which is required for have internet connection or pipewire for audio)
pacman --noconfirm -S xdg-desktop-portal-wlr networkmanager network-manager-applet dialog wpa_supplicant mtools dosfstools avahi xdg-user-dirs xdg-utils gvfs nfs-utils inetutils dnsutils alsa-utils pipewire pipewire-alsa pipewire-pulse pipewire-jack openssh rsync acpi acpi_call ipset sof-firmware nss-mdns acpid ntfs-3g xclip brightnessctl pacman-contrib mesa man-db man-pages ttf-firacode-nerdThis packages are optional, like bluez (Bluetooth), cups (for printers), extra fonts, and some utilities like decompression of zip files ...
pacman --noconfirm -S bluez bluez-utils cups cups-pdf exa bat duf btop zip unzip fastfetch ttf-firacode-nerdInstall a Desktop Environment or Windows Manager of your choice:
KDE PLASMA (D.E.)...
pacman --noconfirm -S sddm plasma-desktop plasma-metaCOSMIC (D.E.)...
pacman -S --noconfirm -S sddm cosmicHYPRLAND (W.M.)...
pacman -S --noconfirm -S sddm hyprlandFor install the GPU drivers of Intel & AMD GPUs you can just do ...
pacman --noconfirm -S mesaBut for NVIDIA is a bit more tricky, you can follow this guide How install NVIDIA Drivers on Arch Linux but I recommend follow it after we finish the installation of Arch, because we don't installed GRUB yet.
Set locale (example: my local isen_US.UTF-8) ...
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
locale-gen
echo "LANG=en_US.UTF-8" >> /etc/locale.confList available layouts ...
localectl list-keymapsOptional: You can filter the layouts with grep (example: for filter usbased keyboards) ...
localectl list-keymaps | grep usI have a latinoamerican-based keyboard, so, in my case I should use la-latin1...
echo "KEYMAP=la-latin1" >> /etc/vconsole.confSet a system-wide default editor (example: micro) ...
echo "EDITOR=micro" > /etc/environment && echo "VISUAL=micro" >> /etc/environmentecho "arch" >> /etc/hostname
echo "127.0.0.1 localhost" >> /etc/hosts
echo "::1 localhost" >> /etc/hosts
echo "127.0.1.1 arch.localdomain arch" >> /etc/hostspasswd rootReplace [USERNAME] with your desired name ...
useradd -m -G wheel [USERNAME]
passwd [USERNAME]Add the users to group wheel, uncomment#%wheel ALL=(ALL:ALL) ALL ...
EDITOR=micro sudo -E visudo
usermod -aG wheel [USERNAME]Set necessary MODULES ,BINARIES and HOOKS in /etc/mkinitcpio.conf:
micro /etc/mkinitcpio.confOn the line MODULES and BINARIES:
MODULES=(usbhid atkbd)
BINARIES=(btrfs setfont)On the line HOOKS:
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt lvm2 resume filesystems fsck)Recreate the initramfs image ...
mkinitcpio -PWe will configure GRUB for point to the encrypted disk and enable hibernation.
Determine the UUID of the [ROOT] encrypted partition ...
# UUID FROM ENCRYPTED DISK
blkid /dev/nvme0n1p2 -o value -s UUIDEdit the line GRUB_CMDLINE_LINUX_DEFAULT on /etc/default/grub:
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet cryptdevice=UUID=UUID-OF-ENCRYPTED-PARTITION:cryptroot root=/dev/mapper/cryptroot resume=/dev/mapper/cryptswap"Example: If the UUID of the encrypted partition was 180901b5-151a-45e3-ba87-28f02b124666, then ...
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet cryptdevice=UUID=180901b5-151a-45e3-ba87-28f02b124666:cryptroot root=/dev/mapper/cryptroot resume=/dev/mapper/cryptswap"Uncomment the line GRUB_ENABLE_CRYPTODISK:
GRUB_ENABLE_CRYPTODISK=yEdit the line GRUB_PREOLOAD_MODULES:
GRUB_PRELOAD_MODULES="part_gpt part_msdos cryptodisk luks2"Save the file with CTRL + S and then run this command for install GRUB on the ESP (EFI) partition ...
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUBGenerate the GRUB config file ...
grub-mkconfig -o /boot/grub/grub.cfgsystemctl enable NetworkManager
systemctl enable bluetooth # Optional
systemctl enable cups.service # Optional
systemctl enable sshd # Optional
systemctl enable avahi-daemon
systemctl enable reflector.timer
systemctl enable fstrim.timer
systemctl enable acpidNow that we installed GRUB, don't forget to install the NVIDIA GPU drivers if you have one, you can do it following this guide: How install NVIDIA Drivers on Arch Linux
Install zram-generator
pacman -S zram-generatorCreate or edit the configuration file /etc/systemd/zram-generator.conf and add ...
[zram0]
# Use 2x RAM size caping to 6GB (adjust multiplier as needed)
zram-size = min(ram * 2, 6144)
compression-algorithm = zstd
swap-priority = 100Apply the configuration ...
sudo systemctl daemon-reload
sudo systemctl start /dev/zram0Verify ZRAM is Active
swapon --show
# OR
cat /proc/swapsWe can finally reboot and unplug the USB installer and start working with our system directly ...
umount -a
exit
rebootWe will be prompted for our password of the encrypted disk, enter that password, wait for start, and then we will be able to use our system!
Install the snapper and snap-pac package for be able to do snapshots automatically ...
$ sudo pacman -S snapper snap-pacSnapper's create-config command assumes:
- Subvolume
@already exists and is mounted at/. /.snapshotsdirectory is not mounted and doesn't exist.
During the Arch install, we created the @ and @snapshots subvolumes, and /.snapshots mountpoint. Before letting Snapper do its config, so, we need to move the earlier snapshot setup.
Unmount the subvolume and remove the mountpoint ...
$ sudo umount /.snapshots
$ sudo rm -rf /.snapshotsCreate a new root config ...
$ sudo snapper -c root create-config /This generates:
- Configuration file at
/etc/snapper/configs/root. - Add
roottoSNAPPER_CONFIGSin/etc/conf.d/snapper. - Subvolume
.snapshotswhere future snapshots for this configuration will be stored.
List subvolumes ...
$ sudo btrfs subvolume list /
ID 256 gen 232 top level 5 path @
ID 257 gen 230 top level 5 path @cache
ID 258 gen 226 top level 5 path @home
ID 259 gen 9 top level 5 path @snapshots
ID 260 gen 232 top level 5 path @log
ID 261 gen 16 top level 256 path var/lib/portables
ID 262 gen 16 top level 256 path var/lib/machines
ID 263 gen 232 top level 256 path .snapshotsNote the @snapshots subvolume we created before, and the .snapshots created by Snapper.
We will delete the Snapper-generated subvolume, letting alone our @snapshots ...
$ sudo btrfs subvolume delete /.snapshots
Delete subvolume (no-commit): '//.snapshots'Re-create and re-mount /.snapshots mountpoint ...
$ sudo mkdir /.snapshots
$ sudo mount -aSet permissions. Owner must be root, and we need allow members of wheel (our user) to browse through snapshots ...
$ sudo chmod 750 /.snapshots
$ sudo chown :wheel /.snapshotsExample of taking a manual snapshot our install ...
$ sudo snapper -c root create -d "Arch encrypted!"Setup timed auto-snapshots by modifying /etc/snapper/configs/root.
Allow user (example: kurami) to work with snapshots ...
$ micro /etc/snapper/configs/root
ALLOW_USERS="kurami"Example: For of some auto-cleanup snapshots limits ...
TIMELINE_MIN_AGE="3600"
TIMELINE_LIMIT_HOURLY="10"
TIMELINE_LIMIT_DAILY="10"
TIMELINE_LIMIT_WEEKLY="0"
TIMELINE_LIMIT_MONTHLY="10"
TIMELINE_LIMIT_QUARTERLY="0"
TIMELINE_LIMIT_YEARLY="0"Start and enable snapper-timeline.timer to launch the automatic snapshot timeline, and snapper-cleanup.timer to periodically clean up older snapshots...
$ sudo systemctl enable --now snapper-timeline.timer
$ sudo systemctl enable --now snapper-cleanup.timerPacman pre- and post- snapshots are triggered before and after we install / update a package on our system.
Example: I install fastfetch, which triggers a pre and post install snapshot.
List configs ...
$ snapper list-configs
Config | Subvolume
-------+----------
root | /List snapshots taken for root ...
$ snapper -c root list
# | Type | Pre # | Date | User | Cleanup | Description | Userdata
---+--------+-------+-----------------------------+------+----------+-------------------------+---------
0 | single | | | root | | current |
1 | single | | Wed 14 Aug 2025 08:17:17 PM | root | | Arch encrypted! |
2 | pre | | Wed 14 Aug 2025 08:18:02 PM | root | number | pacman -S fastfetch |
3 | post | 2 | Wed 14 Aug 2022 08:18:03 PM | root | number | fastfetch |List updated subvolumes list, which now includes the snapshots ...
$ sudo btrfs subvolume list /
ID 256 gen 253 top level 5 path @
ID 257 gen 252 top level 5 path @cache
ID 258 gen 226 top level 5 path @home
ID 259 gen 253 top level 5 path @snapshots
ID 260 gen 256 top level 5 path @log
ID 261 gen 16 top level 256 path var/lib/portables
ID 262 gen 16 top level 256 path var/lib/machines
ID 264 gen 238 top level 259 path @snapshots/1/snapshot
ID 265 gen 251 top level 259 path @snapshots/2/snapshot
ID 266 gen 252 top level 259 path @snapshots/3/snapshotIf locate is installed, skip indexing .snapshots directory by adding to /etc/updatedb.conf ...
PRUNENAMES = ".snapshots"On the installation we did before, we installed GRUB-BTRFS alongside GRUB, which will include the snapshots as boot options in the GRUB boot loader menu.
Set the location of the directory containing the grub.cfg file in /etc/default/grub-btrfs/config.
Our grub.cfg (if you followed the install guide) is located in /boot/grub ...
$ micro /etc/default/grub-btrfs/config
# Search for the line and uncomment it
GRUB_BTRFS_GRUB_DIRNAME="/boot/grub"Enable grub-btrfsd.service to auto-regenerate grub-btrfs.cfg whenever a modification appears in /.snapshots ...
$ sudo systemctl enable --now grub-btrfsd.service
$ sudo grub-mkconfig -o /boot/grub/grub.cfgAt the next boot, we will have an submenu in GRUB for our Arch Linux snapshots.
Booting on a snapshot is done in read-only mode.
Using overlayfs, the booted snapshot will behave like a live-cd in non-persistent mode. The snapshot will not be modified, the system will be able to boot correctly, because a writeable folder will be included in the RAM ... Any changes in this system thus started will be lost when the system is rebooted/shutdown.
Add the hook grub-btrfs-overlayfs at the end of HOOKS in /etc/mkinitcpio.conf ...
HOOKS=(base udev ... fsck grub-btrfs-overlayfs)Re-generate initramfs ...
$ sudo mkinitcpio -PNote: Any snapshots that do not include this modified initramfs will not be able to use overlayfs. (like the example snapshot of earlier).
Snapper includes a rollback tool, but on Arch systems the preferred method is a manual rollback.
After booting into a snapshot mounted using overlayfs, we need to mount the toplevel subvolume. That is, omit any subvolid or subvol mount flags (example: an encrypted device map labelled cryptdev) ...
$ sudo mount /dev/mapper/cryptdev /mntMove the broken @ subvolume out of the way ...
$ sudo mv /mnt/@ /mnt/@.brokenOr simply delete the subvolume ...
$ sudo btrfs subvolume delete /mnt/@Find the number of the snapshot that you want to recover ...
$ sudo grep -r '<date>' /mnt/@snapshots/*/info.xml
[...]
/.snapshots/8/info.xml: <date>2022-08-20 15:21:53</date>
/.snapshots/9/info.xml: <date>2022-08-20 15:22:39</date>Create a read-write snapshot of the read-only snapshot taken by Snapper ...
$ sudo btrfs subvolume snapshot /mnt/@snapshots/number/snapshot /mnt/@Where number is the snapshot you wish to restore as the new @.
Unmount /mnt.
reboot via terminal or by GUI.



