You Ran the Update. The X Server Didn’t Survive.
It’s a Tuesday evening. You run dnf update on your Fedora workstation, reboot, and the display manager refuses to start. You stare at a blinking cursor. You know something in that package batch broke the Nvidia driver handshake, but you have no idea which one and no fast way back.
If you were on openSUSE with Snapper configured, this conversation ends here: you reboot, pick the pre-update snapshot from GRUB, log into your working system, run one command to roll back, and carry on with your evening. Instead you’re Googling nouveau driver black screen fedora 41 at midnight.
That’s the pitch. Let’s set it up properly.
What Snapper Actually Is
Snapper started as an openSUSE project and is now distro-agnostic. It’s a command-line tool (and optionally a daemon) that manages Btrfs snapshots — creating them, scheduling them on a timeline, cleaning up old ones by configurable retention policies, and integrating with package managers so every install/remove gets an automatic before/after pair.
The key insight is that Btrfs snapshots are near-instant and almost free at creation time because they’re copy-on-write. The space cost only accumulates as the live filesystem diverges from the snapshot. A fresh snapshot of your root costs roughly nothing. That’s what makes “snapshot before every update” actually practical, unlike rsync-based approaches.
Snapper handles:
- Timeline snapshots — hourly, daily, weekly, monthly backups on a schedule
- Pre/post snapshots — bracketing package manager transactions
- Cleanup algorithms — trimming old snapshots so your disk doesn’t fill up
- Rollback — a single command that makes a snapshot the new active root
The Subvolume Layout That Makes This Work
Here’s where a lot of people stub their toes. Snapper snapshots live inside the Btrfs filesystem. If your entire root is one flat Btrfs volume with no subvolume structure, snapshots of / will include /home, /var/log, /var/cache — and rolling back will also roll back your home directory to the state it was in before the update. That’s almost never what you want.
The correct layout, which openSUSE ships by default and which you should replicate on any distro:
Btrfs pool (mounted at /mnt during install)├── @ → mounted at /├── @home → mounted at /home├── @var → mounted at /var (or @var-log at /var/log)├── @tmp → mounted at /tmp (or just noatime on @)└── @snapshots → .snapshots directory (managed by snapper)When Snapper snapshots @, it creates a read-only copy of just the root subvolume. Your home directory lives in @home and is completely unaffected. Your package cache in @var doesn’t bloat the snapshot chain.
Check your current layout:
sudo btrfs subvolume list /If you’re installing fresh, set this up during partitioning. If you’re retrofitting an existing Btrfs root with no subvolumes, this is a painful migration — you’ll need to boot from a live USB, create the subvolume structure, and move data. Worth doing right the first time.
Your /etc/fstab should look roughly like this for a properly segmented layout:
UUID=<your-uuid> / btrfs subvol=@,compress=zstd,noatime 0 0UUID=<your-uuid> /home btrfs subvol=@home,compress=zstd,noatime 0 0UUID=<your-uuid> /var btrfs subvol=@var,compress=zstd,noatime 0 0UUID=<your-uuid> /.snapshots btrfs subvol=@snapshots,noatime 0 0The @snapshots subvolume being separate matters: it means snapshots themselves don’t get recursively snapshotted when you snapshot @.
Installing Snapper
Fedora / RHEL
sudo dnf install snapper python3-dnf-plugin-snapper grub-btrfsDebian / Ubuntu
sudo apt install snapper snapper-gui inotify-tools# apt hooks require a bit more manual setup — covered belowopenSUSE
It’s already installed and pre-configured. Lucky you.
Arch Linux
sudo pacman -S snapper snap-pac grub-btrfsFirst-Time Configuration
Create a Snapper config for your root filesystem:
sudo snapper -c root create-config /This creates /etc/snapper/configs/root and the /.snapshots directory inside your Btrfs pool. Take a look at what it generated:
sudo cat /etc/snapper/configs/rootThe key fields you’ll want to tune:
SUBVOLUME="/"FSTYPE="btrfs"
# Timeline snapshot creationTIMELINE_CREATE="yes"TIMELINE_CLEANUP="yes"
# Retention countsTIMELINE_LIMIT_HOURLY="5"TIMELINE_LIMIT_DAILY="7"TIMELINE_LIMIT_WEEKLY="0"TIMELINE_LIMIT_MONTHLY="0"TIMELINE_LIMIT_YEARLY="0"
# Number-based cleanup for pre/post pairsNUMBER_CLEANUP="yes"NUMBER_MIN_AGE="1800"NUMBER_LIMIT="50"NUMBER_LIMIT_IMPORTANT="10"For a homelab root filesystem, TIMELINE_LIMIT_DAILY="7" and NUMBER_LIMIT="50" are reasonable starting points. Tune them based on how much free space you have and how often things break.
Enable and start the timer:
sudo systemctl enable --now snapper-timeline.timersudo systemctl enable --now snapper-cleanup.timerTake a manual snapshot to confirm it works:
sudo snapper -c root create --description "initial baseline"sudo snapper -c root listOutput looks like:
# | Type | Pre # | Date | User | Cleanup | Description | Userdata---+--------+-------+--------------------------+------+---------+---------------------+---------0 | single | | | root | | current |1 | single | | Fri May 23 10:14:22 2026 | root | | initial baseline |Pre/Post Hooks Around Package Managers
This is where Snapper gets genuinely useful. The package manager plugin intercepts every install, update, or remove, takes a snapshot before, runs the transaction, then takes a snapshot after. You end up with matched pairs you can diff or roll back from.
Fedora / DNF
sudo dnf install python3-dnf-plugin-snapperThat’s it. From now on, every dnf install or dnf update automatically creates a pre/post pair. Test it:
sudo dnf install htopsudo snapper -c root listYou’ll see a pre and post pair tagged with the package name.
openSUSE / Zypper
The snapper-zypp-plugin package handles this. On openSUSE Tumbleweed it’s already active. On Leap you may need:
sudo zypper install snapper-zypp-pluginDebian / Ubuntu (apt)
Apt doesn’t have a first-class plugin for this, but you can wire it up with apt hooks in /etc/apt/apt.conf.d/80snapper:
DPkg::Pre-Invoke { "snapper -c root create --description 'pre-apt' --cleanup-algorithm number --userdata 'important=yes'"; };DPkg::Post-Invoke { "snapper -c root create --description 'post-apt' --cleanup-algorithm number --userdata 'important=yes'"; };Crude but functional. The important=yes userdata flag keeps these from being swept up by the aggressive number-based cleanup.
Booting Into a Snapshot with grub-btrfs
A rollback command is great, but sometimes you need to boot into a snapshot first — like when your system won’t boot at all and you need to assess the damage before committing to anything.
grub-btrfs scans your Btrfs snapshots and adds them as GRUB boot entries automatically.
# Fedorasudo dnf install grub-btrfs
# Archsudo pacman -S grub-btrfs
# Then update GRUBsudo grub2-mkconfig -o /boot/grub2/grub.cfg # Fedora/RHELsudo grub-mkconfig -o /boot/grub/grub.cfg # Debian/ArchEnable the inotify watcher so GRUB entries update whenever a snapshot is created:
sudo systemctl enable --now grub-btrfsdOn next reboot, you’ll see a “Arch Linux snapshots” (or distro equivalent) submenu in GRUB. Boot into one, poke around, and if everything looks good, roll back.
Rolling Back: The Actual Point of All This
You booted into a snapshot and confirmed the pre-update state is working. Now you want to make it permanent.
First, identify your snapshot numbers:
sudo snapper -c root list # | Type | Pre # | Date | User | Cleanup | Description | Userdata---+--------+-------+--------------------------+------+---------+----------------------+---------0 | single | | | root | | current |14 | pre | | Tue May 20 19:02:11 2026 | root | number | dnf update |15 | post | 14 | Tue May 20 19:04:33 2026 | root | number | dnf update |16 | single | | Tue May 20 20:00:01 2026 | root | timeline| timeline |Your broken update is wrapped in snapshots 14 (pre) and 15 (post). You want to roll back to 14:
sudo snapper -c root rollback 14Snapper creates a new writable subvolume from snapshot 14 and sets it as the default Btrfs subvolume. On next reboot, you’re back to your pre-update state.
Reboot:
sudo rebootAfter reboot, confirm you’re on the rolled-back system:
sudo snapper -c root list# You'll see a new "rollback" snapshot documenting what happenedYou can also diff between any two snapshots to see exactly what files changed:
sudo snapper -c root diff 14 15Outputs a diff of every changed file — incredibly useful for hunting down which config file a package update clobbered.
Checking Disk Space
This is where people get surprised. Snapshots accumulate. Let’s look at the real picture:
sudo snapper -c root listsudo btrfs filesystem df /Data, single: total=28.00GiB, used=22.14GiBSystem, single: total=4.00MiB, used=16.00KiBMetadata, single: total=1.00GiB, used=456.41MiBGlobalReserve, single: total=128.00MiB, used=0.00BThe metadata section grows as snapshots accumulate. Run the cleanup manually if you’re burning through space:
sudo snapper -c root cleanup timelinesudo snapper -c root cleanup numberOr check how much space each snapshot is contributing:
sudo btrfs filesystem du -s /.snapshots/*/snapshotIf you’ve got 6 months of hourly snapshots and nobody touched the cleanup timer, that number can get uncomfortable.
The Gotcha: Snapshots Are Not Backups
Say it with me: a Btrfs snapshot is not a backup.
It lives on the same disk as your live data. Disk dies → you lose the live filesystem and every snapshot on it. RAID is not a backup either — it protects against drive failure, not accidental deletion or ransomware.
Snapshots are an undo button. Backups are your insurance policy.
To turn snapshots into something backup-adjacent, use btrfs send and btrfs receive to ship them to another pool:
# Send the first snapshot (full)sudo btrfs send /.snapshots/1/snapshot | sudo btrfs receive /mnt/backup/root/
# Send incremental updates (much faster)sudo btrfs send -p /.snapshots/1/snapshot /.snapshots/14/snapshot | \ sudo btrfs receive /mnt/backup/root/Tools like btrbk wrap this into a proper scheduled backup workflow with retention policies and remote send over SSH. It’s worth setting up alongside Snapper rather than treating Snapper as your sole safety net.
How It Compares
Timeshift — Popular on Ubuntu/Mint, works on both ext4 (rsync mode) and Btrfs (snapshot mode). Friendlier GUI, but opinionated about the subvolume layout and doesn’t integrate with package managers. Great for desktop users who don’t want to touch a terminal.
ZFS Boot Environments — ZFS’s answer to the same problem. zectl or beadm manage boot environments (essentially whole-pool snapshots you can boot into). More powerful and truly atomic across datasets, but ZFS is a different filesystem entirely with its own licensing drama. If you’re already on ZFS, Boot Environments are excellent and arguably more robust than Snapper.
Snapper’s edge is the package manager integration. The pre/post pairing means you know exactly which transaction caused a problem without having to remember what you did yesterday. That’s the feature that makes the whole thing practical rather than a theoretical safety net you never actually use.
The Bottom Line
Snapper on a properly laid-out Btrfs root is the closest Linux gets to the “time machine” rollback experience that openSUSE users have been taking for granted for years. The setup is maybe an hour if you’re starting from scratch with the right subvolume layout — and zero effort after that because the package manager hooks handle everything automatically.
The workflow that actually works: install Snapper, configure the subvolume layout correctly (do not skip this), enable the DNF/apt/zypper plugin, install grub-btrfs, and then forget about it until something breaks. When something breaks, you’ll be glad you did.
Pair it with btrbk shipping incremental snapshots to external storage and you’ve got both an undo button and a real backup. That’s the combination worth running. Snapshots alone are a seatbelt. Snapshots plus off-pool backups are the seatbelt and the airbag.
Your 2 AM self — the one staring at a broken X server after a kernel update — will thank you.