How to Use Btrfs Snapshots on the System Disk (Roll Back a Bad Update in One Command)

ZFS (97) is the right thing for the data drives, but it's awkward as the root filesystem on Ubuntu and wants memory. Btrfs is built into the kernel, happy on a 2 GB box, and does the thing you most want on a system disk: a snapshot before every update, and a rollback — from the GRUB menu if need be — when a kernel or Docker release breaks something (75, 63). With Snapper it's automatic.
Quick reference
| Task | Command | |
|---|---|---|
| Install Ubuntu on Btrfs | installer → custom storage → root as btrfs (creates @ and @home) | |
| Snapper for root | sudo snapper -c root create-config / | |
| Snapshot before/after apt | automatic with snapper + the apt-btrfs-snapshot hook or Snapper's apt plugin | |
| List | sudo snapper -c root list | |
| Undo a change to one file | sudo snapper -c root undochange 12..13 /etc/nginx/nginx.conf | |
| Roll the whole root back | sudo snapper -c root rollback 12 then reboot | |
| Boot into a snapshot | grub-btrfs adds them to the GRUB menu | |
| Send to another disk | `btrfs send -p old new | btrfs receive /mnt/backup/` |
1. Install on Btrfs
On a fresh install (1), Custom storage layout: the root partition formatted as btrfs, mounted at /. Ubuntu's installer creates two subvolumes — @ (root) and @home — which is what makes rollbacks clean: you snapshot and replace @ without touching @home. /boot/efi stays FAT; /boot can live inside @.
Already installed on ext4? Converting in place is possible (btrfs-convert) but a reinstall with restore (74, 140) is less risky. Or apply this to a new server.
Check: sudo btrfs subvolume list /.
2. Mount options worth having
In /etc/fstab, the root line:
UUID=… / btrfs defaults,subvol=@,compress=zstd:1,noatime,discard=async 0 0
zstd:1 compression is free space at no measurable cost; discard=async for an SSD. sudo mount -o remount / and sudo btrfs filesystem defrag -r -czstd / once to compress what's there.
3. Snapper
sudo apt install snapper -y
sudo snapper -c root create-config /
sudo snapper -c home create-config /home
sudo snapper -c root list
Snapper makes a .snapshots subvolume and a timeline: hourly snapshots, thinned to daily/weekly/monthly (/etc/snapper/configs/root — set TIMELINE_LIMIT_HOURLY="12", NUMBER_LIMIT="20"). For the apt hook on Ubuntu:
sudo apt install apt-btrfs-snapshot -y
(or Snapper's own snapper-apt plugin where packaged) — every apt install/upgrade gets a pre and post snapshot, so "what did that update change?" is snapper status.
sudo snapper -c root create -d "before docker upgrade"
sudo apt upgrade -y
sudo snapper -c root list
4. Undo
One file:
sudo snapper -c root diff 12..13 /etc/ssh/sshd_config
sudo snapper -c root undochange 12..13 /etc/ssh/sshd_config
The whole root, after a bad update:
sudo snapper -c root rollback 12
sudo reboot
Snapper makes the old snapshot the new default @ and keeps the broken state as a snapshot too. /home is a separate subvolume, so nothing you wrote today is lost. Docker's /var/lib/docker is inside @ — put it on its own subvolume (@docker, mounted at /var/lib/docker, excluded from root snapshots) or your container images roll back with the OS, which is usually fine but slow to re-pull.
5. Roll back from GRUB when it won't boot
sudo apt install grub-btrfs -y
sudo systemctl enable --now grub-btrfsd
sudo update-grub
The GRUB menu gains a Snapshots entry listing every Snapper snapshot. A kernel update that panics (75, case 3): pick yesterday's snapshot, boot read-only into it, then snapper rollback from there. No live USB.
6. Send snapshots elsewhere
A Btrfs snapshot can be streamed to another Btrfs disk — the system equivalent of ZFS send:
sudo btrfs send /.snapshots/13/snapshot | sudo btrfs receive /mnt/backup/root-snaps/
sudo btrfs send -p /.snapshots/13/snapshot /.snapshots/14/snapshot | sudo btrfs receive /mnt/backup/root-snaps/
The -p form sends only the difference. btrbk automates this with retention. Together with restic for the data (55), the whole machine is recoverable to the hour.
Btrfs for data drives?
It does mirrors (-d raid1 -m raid1) with checksums and self-healing like ZFS, in the kernel, with less RAM. Avoid RAID5/6 on Btrfs (still not safe). Many home servers run Btrfs root + ZFS data, or Btrfs everywhere on small boxes.
Troubleshooting
Disk fills though df says space. Old snapshots hold deleted data. sudo snapper -c root cleanup number and lower the limits; sudo btrfs filesystem usage / shows the truth.
"No space left" during balance/snapshot. Metadata exhausted: sudo btrfs balance start -musage=50 /.
Rollback didn't take. The default subvolume wasn't changed (btrfs subvolume get-default /); Snapper's rollback needs the @-style layout.
Scrub, like ZFS. sudo btrfs scrub start / monthly; scrub status for errors.
Wrapping up
Ubuntu on Btrfs with @ and @home, Snapper with the apt hook, grub-btrfs for the menu, btrfs send to the backup disk. A broken update becomes a reboot into yesterday, and the system disk gets the undo button the data drives already had.
