Add a BTRFS snapshots guide and mention it as an advanced install option
This commit is contained in:
@@ -319,6 +319,10 @@ Install and deploy Arcane
|
||||
::card{icon="i-lucide-database-backup" title="3-2-1 Backups" to="/serveex/advanced/backrest"}
|
||||
Install and deploy Backrest
|
||||
::
|
||||
|
||||
::card{icon="i-lucide-rotate-ccw" title="Instant Rollback" to="/serveex/advanced/btrfs-snapshots"}
|
||||
Set up BTRFS snapshots
|
||||
::
|
||||
::
|
||||
|
||||
## Coming Soon
|
||||
|
||||
@@ -97,6 +97,10 @@ Finish with *Finish partitioning and write changes to disk*, then confirm with *
|
||||
✨ __Tip:__ what actually lives on that one partition, and why `/srv/docker` is where this guide puts every stack, is covered in **folders and partitions**.
|
||||
::
|
||||
|
||||
::tip{icon="" to="/serveex/advanced/btrfs-snapshots"}
|
||||
✨ __For advanced users:__ picking *Manual* here instead of *Guided* lets you format the root partition as Btrfs instead of ext4, unlocking instant, near-free snapshots you can roll back to before a risky update or config change. It's not a replacement for real backups, a snapshot lives on the same disk, see **BTRFS snapshots** if you want to set it up.
|
||||
::
|
||||
|
||||
#### Mirror and surveys
|
||||
|
||||
Answer *No* to *Scan another installation medium?*, everything else comes from the network. For the mirror, pick any one in your country, or `deb.debian.org` which routes to a nearby one automatically, and leave the HTTP proxy field empty unless you actually have one. The popularity contest (anonymous package statistics) is yes or no, no consequence either way.
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
---
|
||||
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.
|
||||
Reference in New Issue
Block a user