7.6 KiB
title, description
| title | description |
|---|---|
| BTRFS Snapshots | Format Debian's root filesystem with BTRFS and use Snapper to instantly roll back a risky update or config change, as a local complement to Backrest's off-site 3-2-1 backups. |
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
BTRFS is a Linux filesystem with one killer feature for a homelab: snapshots. A snapshot freezes the exact state of a filesystem in an instant, at essentially zero cost, without copying a single byte of data upfront. Break something ten minutes after an apt full-upgrade, or overwrite the wrong .env file, and you can go back to exactly how things were before, without touching a backup at all.
This is not what Backrest and the 3-2-1 rule are for, so it's worth being precise about the difference before setting anything up.
Snapshots are not backups
A snapshot lives on the exact same disk as the data it protects. It's instant, needs no network, and it's perfect for undoing a mistake you just made, but it does nothing at all the day that disk itself dies, gets stolen, or your server burns down. That's what a real 3-2-1 backup is for: a copy on different media, ideally off-site.
Think of it this way:
- Snapshot = an undo button. Instant, local, cheap, only useful while the disk is alive.
- Backup = insurance. Slower, off-site, the only thing that survives the disk itself failing.
Keep both. Snapshots make you fearless about updates and experiments, backups make sure a dead drive stays an inconvenience instead of a catastrophe.
::note{to="/serveex/core/installation#partitioning"}
This guide assumes the root partition was formatted with Btrfs during Debian's installation. Btrfs can't be safely bolted onto an existing ext4 root after the fact, so this is a choice you make once, at install time. ::
Formatting the root partition with BTRFS
Debian's Guided partitioning only ever offers ext4. To get Btrfs, pick Manual partitioning instead, at the same step the main install guide describes:
::steps{level="3"}
Select Manual partitioning
At the partitioning method screen, choose Manual instead of Guided - use entire disk.
Create a partition table
Select the disk, confirm creating a new empty partition table, then select the resulting FREE SPACE and choose Create a new partition.
Set the partition size and type
Give the partition the rest of the disk (minus a small EFI partition if you're on UEFI, handled the same way as a Guided install), and set Use as to Btrfs journaling file system, with the mount point /.
Finish partitioning
Finish partitioning and write changes to disk, then confirm with Yes.
Done!
::
Everything else in the installer stays the same.
Installing Snapper
Rather than juggling raw btrfs subvolume commands by hand, Snapper is a small tool that manages the whole snapshot lifecycle: creating them, storing them tidily, pruning old ones, and automatically bracketing every apt operation with a snapshot pair.
sudo apt install snapper
sudo snapper -c root create-config /
create-config registers a config named root for the / filesystem, and creates a dedicated .snapshots subvolume under it to store every snapshot, locked down to root. No @/@home subvolume split needed, this works fine on the plain single-subvolume layout the manual partitioning above just created.
Turn the config on by editing /etc/default/snapper:
SNAPPER_CONFIGS="root"
Then enable the timers that run Snapper's periodic snapshots and cleanup:
sudo systemctl enable --now snapper-timeline.timer snapper-cleanup.timer
::note
Debian's package also ships an APT hook (/etc/apt/apt.conf.d/80snapper) that kicks in the moment a config is listed in SNAPPER_CONFIGS: from now on, every apt install, apt upgrade or apt full-upgrade automatically gets a snapshot right before and right after it runs, with zero extra effort on your part.
::
Taking a snapshot
For anything outside apt, like editing a systemd unit or a Docker Compose file, take one yourself with a description that will actually mean something later:
sudo snapper create --description "before compose change on swag"
List every snapshot with:
sudo snapper list
# | Type | Pre # | Date | Description
---+--------+-------+--------------------------+---------------------------------
0 | single | | | current
1 | single | | Tue 09 Sep 2026 18:30:00 | before compose change on swag
2 | pre | | Tue 09 Sep 2026 19:00:01 | apt install unattended-upgrades
3 | post | 2 | Tue 09 Sep 2026 19:00:14 | apt install unattended-upgrades
Restoring files from a snapshot
Snapper keeps the full state of the filesystem at snapshot time under /.snapshots/<number>/snapshot, browsable like any other folder:
ls /.snapshots/1/snapshot/etc/ssh/
To see exactly what changed between a snapshot and the live system (0 always means "current") before touching anything:
sudo snapper status 1..0
That prints every file created, modified or deleted since. To undo those changes automatically:
sudo snapper undochange 1..0
Or restore a single file by hand, which is often the safer, more surgical choice:
sudo cp -a /.snapshots/1/snapshot/etc/ssh/sshd_config /etc/ssh/sshd_config
::note
This covers the vast majority of real homelab accidents: a bad config, a deleted file, a package upgrade that broke one thing. Snapper can also rollback the entire root filesystem to an earlier snapshot (it creates a new default subvolume and boots into it on the next restart), for a system in a genuinely bad state rather than just missing one file. It's a more delicate, less common operation, worth testing once on a machine you don't mind rebooting before you actually need it for real. And if the disk itself is the problem, that's exactly the scenario your off-site Backrest backup is for anyway.
::
Managing and pruning snapshots
Snapshots are cheap, not free: the moment the live filesystem diverges from one, the old blocks it still references stick around. Left unchecked, months of snapshots on a server that changes a lot (container images, logs) can quietly eat real disk space.
The snapper-cleanup.timer enabled above already prunes automatically, based on the config at /etc/snapper/configs/root:
| Setting | Default | What it does |
|---|---|---|
TIMELINE_LIMIT_HOURLY / _DAILY / _MONTHLY / _YEARLY |
10 |
How many timeline snapshots of each granularity to keep |
TIMELINE_LIMIT_WEEKLY |
0 |
Off by default |
NUMBER_LIMIT |
50 |
How many manual (single) snapshots to keep |
Adjust these to taste, then delete one immediately by hand if you need the space back right now:
sudo snapper delete 1
Check actual disk usage with df -h /: the numbers above only cap how many snapshots exist, not the space a very active server can still burn through between cleanups.
That's it: a rolling, automatic undo button for your server, quietly bracketing every update and pruning itself, running alongside the real backups Backrest is already taking off-site.