--- title: BTRFS Snapshots description: Format Debian's root filesystem with BTRFS and use snapshots 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](https://btrfs.readthedocs.io/) 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](/serveex/advanced/backrest) 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](/serveex/advanced/backrest) 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](/serveex/core/installation#partitioning). 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](/serveex/core/installation#partitioning) 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](/serveex/core/installation#install-debian) stays the same. ## Taking a snapshot A snapshot is created with a single command, and completes instantly no matter how much data is on the disk, since Btrfs only starts copying blocks the moment something actually changes (copy-on-write): ```bash [Terminal] sudo mkdir -p /.snapshots sudo btrfs subvolume snapshot -r / /.snapshots/$(date +%F_%H-%M-%S) ``` - `-r` makes it **read-only**, which is what you want for a safety net: nothing, including you by accident, can modify a snapshot after the fact. - Storing snapshots under `/.snapshots` keeps them out of the way, and Btrfs is smart enough not to recurse into a subvolume the next time you snapshot `/` itself, so snapshots never end up containing older snapshots. Take the habit of running this before anything that could go wrong: `sudo apt full-upgrade`, editing a systemd unit, or a Docker Compose change that touches something outside `/srv/docker`. ::tip ✨ Give the snapshot a name that means something instead of just a timestamp, for example `/.snapshots/before-upgrade-2026-09-09`, so you know why it's there when you find it three weeks later. :: ## Restoring files from a snapshot A snapshot is just a folder: everything the filesystem looked like at that instant, browsable like any other directory. ```bash [Terminal] ls /.snapshots/2026-09-09_18-30-00/etc/ssh/ ``` To undo a mistake, copy the file (or folder) back from the snapshot over the current one: ```bash [Terminal] sudo cp -a /.snapshots/2026-09-09_18-30-00/etc/ssh/sshd_config /etc/ssh/sshd_config ``` `-a` preserves permissions and ownership, which matters for anything under `/etc`. ::note This covers the vast majority of real homelab accidents: a bad config, a deleted file, a package upgrade that broke one thing. Rolling back the __entire__ root filesystem (for a system that no longer boots at all) is also possible, by renaming subvolumes from a live USB, but it's a more delicate, less common operation. The [Btrfs documentation](https://btrfs.readthedocs.io/en/latest/Subvolumes.html) covers it if you ever need it, and honestly, if it comes to that, this is exactly the scenario your off-site [Backrest](/serveex/advanced/backrest) backup is for anyway. :: ## Managing snapshots ```bash [Terminal] sudo btrfs subvolume list / ``` Lists every subvolume on the filesystem, snapshots included, each with its own ID. Delete one you no longer need with: ```bash [Terminal] sudo btrfs subvolume delete /.snapshots/2026-09-09_18-30-00 ``` ::caution Snapshots are cheap, not free: the moment the live filesystem diverges from a snapshot, the old blocks stick around for as long as the snapshot references them. A pile of old snapshots on a server that changes a lot (container images, logs) can quietly eat real disk space. Check with `df -h /` and prune what you don't need anymore. :: ## Automating snapshots Rather than remembering to run the command by hand, a small script plus a systemd timer takes one automatically and prunes old ones: ```bash [Terminal] sudo nano /usr/local/bin/btrfs-snapshot.sh ``` ```bash [btrfs-snapshot.sh] #!/bin/bash set -e mkdir -p /.snapshots btrfs subvolume snapshot -r / "/.snapshots/$(date +%F_%H-%M-%S)" # Keep only the 7 most recent snapshots cd /.snapshots ls -1 | sort | head -n -7 | while read -r old; do btrfs subvolume delete "$old" done ``` ```bash [Terminal] sudo chmod +x /usr/local/bin/btrfs-snapshot.sh ``` ```bash [Terminal] sudo nano /etc/systemd/system/btrfs-snapshot.service ``` ```ini [btrfs-snapshot.service] [Unit] Description=Take a Btrfs root snapshot [Service] Type=oneshot ExecStart=/usr/local/bin/btrfs-snapshot.sh ``` ```bash [Terminal] sudo nano /etc/systemd/system/btrfs-snapshot.timer ``` ```ini [btrfs-snapshot.timer] [Unit] Description=Daily Btrfs root snapshot [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target ``` ```bash [Terminal] sudo systemctl daemon-reload sudo systemctl enable --now btrfs-snapshot.timer ``` Check it's scheduled with `systemctl list-timers`, and trigger one right away to test it with `sudo systemctl start btrfs-snapshot.service`. That's it: a rolling, automatic undo button for your server, running quietly alongside the real backups Backrest is already taking off-site.