Snapshots

setup disk made @snapshots for exactly this. setup install configured snapper to keep snapshots of / (the @ subvolume) there, and installed snap-pac, whose pacman hooks take one snapshot before every transaction and one after:

Run this on the new machine:
sudo snapper list
(stdout)
# | Type   | Pre # | Date                     | User | Cleanup | Description               | Userdata
--+--------+-------+--------------------------+------+---------+---------------------------+---------
0 | single |       |                          | root |         | current                   |
1 | pre    |       | Mon Oct 26 05:22:11 2026 | root | number  | pacman -S --noconfirm vim |
2 | post   |     1 | Mon Oct 26 05:22:14 2026 | root | number  | vim                       |

The configuration is in the host repo, at etc/snapper/configs/root:

  • No timeline. Snapshots are taken when something changes, by pacman, not every hour. admin save and admin apply that do not touch packages take none.
  • The newest ten, by NUMBER_LIMIT, pruned by snapper-cleanup.timer once they are an hour old. Pre and post pairs whose contents are identical are pruned too.
  • Only /. @home, @log and @pkg are separate subvolumes so that rolling the system back leaves your data, your logs and the package cache alone.

A snapshot is a read-only btrfs subvolume under /.snapshots/N/snapshot, so it costs only the space of what changed since.

Rolling back

Untested

Undoing a snapshot has not been tried on a machine built by this book yet.

To see what a transaction changed, compare its pre and post snapshot:

Run this on the new machine:
sudo snapper status 1..2

To undo it, on the running system:

Run this on the new machine:
sudo snapper undochange 1..2

That copies back every file in / that changed between the two snapshots – including pacman’s database, which lives in @, so pacman agrees afterwards about which versions are installed. Then admin diff, which should show no drift.

The kernel is not in the snapshot

/boot is the FAT ESP (or the Pi’s firmware partition), not a btrfs subvolume, so no snapshot covers it. If the transaction you undo upgraded the kernel, the old modules come back but /boot still has the new kernel, and the next boot will not find its modules. Before rebooting, reinstall the kernel package – now the older version, from the package cache – so that its hooks rewrite /boot to match: sudo pacman -S linux (linux-rpi-16k on the Pi).

When the system no longer boots at all, boot the stick, then setup host --from and setup disk --mount as in Prepare the disk, and arch-chroot /mnt snapper --no-dbus undochange 1..2 from there.

Booting a snapshot

setup does not write boot entries for snapshots, because a menu that grows an entry every time pacman runs is worse than no menu. But systemd-boot will boot one if you write the entry, and it is the quickest way to answer “was the machine still good at snapshot 1?” before you undo anything.

An entry is the ordinary one with a different subvol. The ESP is mounted fmask=0077, so it takes sudo even to read:

Edit this file: /boot/loader/entries/snapshot-1.conf
title   Arch Linux snapshot 1
linux   /vmlinuz-linux
initrd  /initramfs-linux.img
options root=UUID= rootflags=subvol=@snapshots/1/snapshot ro

@snapshots/1/snapshot is where snapper keeps snapshot 1, as seen from the top of the btrfs filesystem – the same place @ is seen from, which is why arch.conf says subvol=@. Then boot it exactly once, rather than making it the default:

Run this on the new machine:
sudo bootctl set-oneshot snapshot-1.conf
sudo systemctl reboot

What you get is a system you can log into, with / the snapshot: findmnt -no SOURCE / reads /dev/vda2[/@snapshots/1/snapshot], and snapper list marks the booted snapshot with a -. Reading works – pacman -Q answers from the snapshot’s database, which is the whole point of looking.

It boots read-only, whatever the mount says

A snapper snapshot is a read-only subvolume (btrfs property get -ts .../snapshot says ro=true), and that, not the ro on the kernel command line, is what stops writes. findmnt cheerfully reports rw and touch /etc/anything still fails. In the test VM six units failed for that reason, all of them pacman’s gnupg sockets (gpg-agent@etc-pacman.d-gnupg.socket and friends), which want to create sockets under /etc/pacman.d/gnupg.

@home, @log, @pkg and @nix are separate subvolumes that no snapshot covers, so they are still writable – your home directory in a snapshot boot is today’s, not the snapshot’s.

So this is for looking, not repairing: you cannot snapper undochange into a read-only root. Do the repair from the stick, as above. And the kernel and initramfs come from the ESP, which no snapshot covers, so a snapshot from before a kernel upgrade boots today’s kernel – the module mismatch described above applies here too.

Because it was a one-shot, the next boot is the normal system again, with nothing to undo and no failed units. The entry file stays until you delete it; admin diff will not mention it, since /boot is not in the host repo.

// settings
theme:
fx: