Merge pull request 'Add BTRFS snapshots guide, TinyAuth/Pocket ID diagrams, and Backrest restore docs' (#3) from wip into main
Trigger container build / trigger (push) Successful in 6s

Reviewed-on: #3
This commit was merged in pull request #3.
This commit is contained in:
2026-09-09 14:26:08 +02:00
26 changed files with 904 additions and 76 deletions
+1
View File
@@ -42,3 +42,4 @@ __pycache__
# Scratch/demo files (not part of the site) # Scratch/demo files (not part of the site)
scratch scratch
.screenshot
+10
View File
@@ -296,6 +296,8 @@ ui:
icon: text-[#175DDC] icon: text-[#175DDC]
--- ---
Install and deploy Vaultwarden Install and deploy Vaultwarden
::
:: ::
:: ::
@@ -313,6 +315,14 @@ Install and deploy Authentik
::card{icon="i-noto-crystal-ball" title="Multi-host Docker manager" to="/serveex/advanced/arcane"} ::card{icon="i-noto-crystal-ball" title="Multi-host Docker manager" to="/serveex/advanced/arcane"}
Install and deploy Arcane 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 ## Coming Soon
@@ -89,6 +89,10 @@ Confirm the timezone guessed from your country.
*Guided, use entire disk* on the system drive, then *All files in one partition*, which gives you one big `/` plus a swap partition. Separate `/home` or `/var` partitions buy you very little here and mostly guarantee that one fills up while the others sit half empty. Pick LVM only if you already know you want snapshots or to grow volumes later. Your data disks are not touched at this stage, you'll mount them afterwards. *Guided, use entire disk* on the system drive, then *All files in one partition*, which gives you one big `/` plus a swap partition. Separate `/home` or `/var` partitions buy you very little here and mostly guarantee that one fills up while the others sit half empty. Pick LVM only if you already know you want snapshots or to grow volumes later. Your data disks are not touched at this stage, you'll mount them afterwards.
::warning{to="/serveex/advanced/btrfs-snapshots"}
__For advanced users:__ this is the moment to decide, not later. 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. Once this step is done and Debian is installed on ext4, switching to Btrfs isn't possible without wiping the disk and starting over. See **BTRFS snapshots** if you want to set it up, it's not a replacement for real backups either, a snapshot lives on the same disk.
::
Finish with *Finish partitioning and write changes to disk*, then confirm with *Yes*: this is the point of no return for that disk. Finish with *Finish partitioning and write changes to disk*, then confirm with *Yes*: this is the point of no return for that disk.
![Debian installer partitioning scheme, all files in one partition](/img/serveex/install/debian-install-partition.png) ![Debian installer partitioning scheme, all files in one partition](/img/serveex/install/debian-install-partition.png)
@@ -15,6 +15,8 @@ It supports a simple local username/password login out of the box, which is what
- [TinyAuth documentation](https://tinyauth.app/docs/getting-started) - [TinyAuth documentation](https://tinyauth.app/docs/getting-started)
- [TinyAuth on GitHub](https://github.com/tinyauthapp/tinyauth) - [TinyAuth on GitHub](https://github.com/tinyauthapp/tinyauth)
![Diagram of TinyAuth sitting behind SWAG as the forward-auth proxy in front of local services](/img/serveex/tinyauth.svg)
## Installation ## Installation
::file-tree ::file-tree
@@ -15,6 +15,8 @@ This makes it a good fit if you just need a simple, fast SSO backend, for exampl
- [Pocket ID documentation](https://pocket-id.org/docs) - [Pocket ID documentation](https://pocket-id.org/docs)
- [Pocket ID on GitHub](https://github.com/pocket-id/pocket-id) - [Pocket ID on GitHub](https://github.com/pocket-id/pocket-id)
![Diagram of Pocket ID acting as the native OIDC identity provider behind SWAG](/img/serveex/pocket-id-native.svg)
## Installation ## Installation
::file-tree ::file-tree
@@ -230,6 +232,8 @@ Save, then copy the generated __Client ID__ and __Client Secret__. You'll need t
## Connecting Pocket ID to TinyAuth ## Connecting Pocket ID to TinyAuth
[TinyAuth](/serveex/security/tinyauth) can delegate its login to Pocket ID instead of (or alongside) its local username/password, so anyone visiting a protected app authenticates with a passkey and gets forwarded through. [TinyAuth](/serveex/security/tinyauth) can delegate its login to Pocket ID instead of (or alongside) its local username/password, so anyone visiting a protected app authenticates with a passkey and gets forwarded through.
![Diagram of TinyAuth delegating login to Pocket ID via OIDC](/img/serveex/pocket-id.svg)
::steps{level="3"} ::steps{level="3"}
### Register TinyAuth as an OIDC client ### Register TinyAuth as an OIDC client
@@ -0,0 +1,253 @@
---
title: Backrest
description: Install Backrest, a friendly web UI for restic, and back up your server properly following the 3-2-1 rule, to a local disk, another server, S3, or Backblaze B2.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
Let's be honest for a second: "backup strategy" for most homelabbers means copying a few folders to a USB stick that one time in 2019, then hoping for the best. [Backrest](https://github.com/garethgeorge/backrest) is here to fix that, without making you learn a scary command-line tool first.
Under the hood, Backrest is a clean web interface on top of [restic](https://restic.net/), a battle-tested, open-source backup engine. Restic does the actual work (encrypting, deduplicating, and shipping your data wherever you tell it to); Backrest gives you buttons and forms instead of a wall of flags to memorize.
![Backrest's dashboard, showing several repositories and their recent backup activity](/img/serveex/backrest-dashboard.png)
## The 3-2-1 rule, or why one backup is not a backup
Before installing anything, let's talk about the rule that actually matters here, because a backup done wrong gives you false confidence, which is worse than no backup at all.
The **3-2-1 rule** says:
- **3** copies of your data: the original, plus at least two backups.
- **2** different types of storage: not two copies sitting on the same disk, or on two disks in the same machine.
- **1** copy offsite: physically somewhere else, not in the same room, house, or building as the original.
Each number closes a specific failure scenario:
- Only **1** backup? A single mistake (a bad `rm -rf`, a botched restore, a corrupted file silently copied over the good one) can take out your only safety net at the same time as the original.
- Backups on the **same type of storage** (say, a second internal drive in the same server)? A power surge, a firmware bug, or a cheap PSU dying can very well take out every disk in the box at once.
- No **offsite** copy? Fire, flood, theft, or "I unplugged the wrong power strip" don't care how many drives you have, if they're all in the same room.
This is also exactly why [RAID is not a backup](/general/storage/raid): RAID keeps a service running when a disk dies, it does nothing against ransomware encrypting every file it can reach, a fat-fingered delete, or your house catching fire. Backrest, pointed at a destination outside your server, is what actually covers those cases.
## What Backrest actually backs up, and where
Two concepts to know before clicking around:
- A **repository** is the destination: an encrypted, deduplicated storage location. This is your "2" and your "1" from the rule above, an external disk, another server, or cloud storage.
- A **plan** is the rule you define: which folders to back up, into which repository, on what schedule, and how many old snapshots to keep around.
You can have several plans backing up to several repositories at once, which is exactly how you'd build a real 3-2-1 setup: one plan to a local repository for quick restores, another plan to an offsite repository for the "my house is on fire" scenario.
## Installation
::file-tree
---
tree:
/:
- srv:
- docker:
- backrest:
- data/
- config/
- cache/
- compose.yaml
---
::
::steps{level="3"}
### Deploy the stack
Open Dockge, click `compose`, name the stack `backrest`, and paste the following:
```yaml [compose.yaml]
---
services:
backrest:
image: garethgeorge/backrest:latest
container_name: backrest
restart: unless-stopped
ports:
- 9898:9898
volumes:
- ./data:/data
- ./config:/config
- ./cache:/cache
# Whatever you want Backrest to be able to back up has to be
# mounted here too: this stack only sees what it's given.
- /srv/docker:/userdata/docker:ro
- /etc:/userdata/etc:ro
- /home:/userdata/home:ro
environment:
- BACKREST_DATA=/data
- BACKREST_CONFIG=/config/config.json
- XDG_CACHE_HOME=/cache
- TZ=Europe/Paris
```
The `/srv/docker`, `/etc` and `/home` lines above cover what's actually worth an off-site backup on a homelab server, per [folders and partitions](/general/linux/filesystem): `/srv/docker` holds every stack's config and data (databases, uploaded files, Vaultwarden's vault, Pocket ID's users, and so on), `/etc` holds your system configuration (the SSH hardening from the [installation guide](/serveex/core/installation#close-the-door-behind-you), your SWAG `.subdomain.conf` files, systemd units), and `/home` holds your own scripts and notes. All three are mounted read-only, a backup tool has no business writing to what it's backing up.
What's usually **not** worth it: a big media library or a torrent download folder sitting on a separate data disk. It's often huge, replaceable, and rarely worth paying for cloud storage or SSH bandwidth to protect.
::tip{icon=""}
✨ __Tip:__ Add the Watchtower label to automate updates
```yaml [compose.yaml]
services:
backrest:
#...
labels:
- com.centurylinklabs.watchtower.enable=true
```
::
Deploy the container, then open `http://yourserverip:9898`. The first visit asks you to set an admin username and password: do it immediately, Backrest has no account by default and the setup screen is wide open until you do.
### Done!
::
## Creating your first repository
![Backrest's Add Restic Repository form, showing a Backblaze B2 repository URI](/img/serveex/backrest.png)
In Backrest, go to **Add Repo**. The form is split into a few sections, here's what each field actually does:
- **Repo Name**: whatever helps you recognize it later, `usb-key` or `offsite-vps` for instance. You can't rename it afterwards, so pick something you won't regret.
- **Auto Unlock**: leave this off unless you understand what it does. Restic locks a repository while it's working on it, so a second process doesn't corrupt things by writing at the same time. Auto Unlock removes that lock automatically on startup, which is convenient if Backrest crashed mid-backup and left a stale lock behind, but genuinely unsafe if two machines ever write to the same repository at once. For the single-server homelab setup this article covers, it's a minor convenience; leave it off if in doubt.
- **Shared**: only relevant to Backrest's multihost feature (several of your machines managing the same repo config). Ignore it for a single server.
- **Repository URI**: where the data actually lives. This is the field that changes for every destination below.
- **Password**: the encryption password for this repository, click **Generate** for a strong random one. **Save it somewhere outside this server**, a password manager, a note on your phone, anywhere but a text file sitting next to the backups it protects. Lose it, and every single backup becomes an expensive pile of unreadable noise, no exceptions, not even for the developers of restic.
- **Env Vars**: where you'll paste credentials for destinations that need them (S3 and B2 below). Local disks and SFTP don't need any.
::note
The **Scheduling**, **Hooks**, and **Advanced** tabs of this form configure repository-wide maintenance (pruning old data, verifying integrity, notifications) rather than anything destination-specific. They're covered at the end of this article, once you've got a repository actually working.
::
### Backing up to a local disk or USB key
The simplest possible offsite copy is a drive you physically move somewhere else after each backup, or a second machine's disk reached over the network. Either way, from Backrest's point of view it's just a folder, so the setup is identical: plug in the drive (or mount the remote share) on the host, add it to the compose file's volumes the same way you did for `/srv/docker` above, then in the Repository URI field, use the path as it appears **inside the container**:
```text
/userdata/backup-drive
```
That's it, no credentials, no Env Vars. This is the fastest repository to restore from too, since there's no network round-trip involved, which makes it a great pick for your "quick recovery" copy, paired with a proper offsite one below for the "my house is on fire" scenario.
::caution
__If it fails:__ the path has to exist and be writable by the container before you submit the form. An empty folder is fine, restic initializes the repository structure itself on first use.
::
### Backing up to another server
No cloud account, no problem: if you have SSH access to another machine, a friend's server, a cheap VPS, a Raspberry Pi at a relative's house, that's a perfectly valid offsite repository, and it costs whatever that machine already costs you.
First, make sure this server can SSH into the other one without typing a password every time:
```bash [Terminal]
ssh-keygen -t ed25519 -f /srv/docker/backrest/config/id_ed25519 -N ""
ssh-copy-id -i /srv/docker/backrest/config/id_ed25519.pub youruser@theotherserver
```
Mount that key into the container by adding it to the compose file's volumes:
```yaml [compose.yaml]
volumes:
# ...
- ./config/id_ed25519:/root/.ssh/id_ed25519:ro
```
Redeploy the stack, then in Backrest use:
```text
sftp:youruser@theotherserver:/path/to/backups
```
::caution
__If it fails:__ the target folder (`/path/to/backups` above) has to already exist on the other server, and that user needs write access to it. SSH there once by hand first (`ssh youruser@theotherserver`) to confirm the connection works and accept the host key, Backrest running inside a container won't get the interactive prompt for that.
::
## Advanced: cloud object storage
A local drive or a friend's spare server covers the 3-2-1 rule perfectly well, and costs nothing beyond what you already own. Cloud object storage is the other classic option, worth it once you want an offsite copy that doesn't depend on anyone's spare hardware staying online, at the cost of a few cents to a few euros a month depending on how much you back up.
### Backblaze B2
[Backblaze B2](https://www.backblaze.com/cloud-storage) is object storage built with exactly this use case in mind, and it's usually the cheapest option for the "write often, read rarely" pattern a backup is.
Create a bucket in your Backblaze account, then generate an **application key** scoped to it. In Backrest, use:
```text
b2:your-bucket-name:backrest
```
With the following Env Vars:
| Variable | Value |
|----------|-------|
| `B2_ACCOUNT_ID` | The application key ID |
| `B2_ACCOUNT_KEY` | The application key itself |
### S3-compatible storage
S3 isn't just an Amazon thing, it's a storage protocol that most cloud providers speak (OVH, Scaleway, MinIO if you self-host your own, and plenty of others), which makes it a solid, portable choice if you'd rather not depend on one specific provider.
Create a bucket with your provider of choice, then in Backrest's Repository URI field, use:
```text
s3:https://s3.your-provider.com/your-bucket-name/backrest
```
For actual AWS S3, drop the custom endpoint:
```text
s3:s3.amazonaws.com/your-bucket-name/backrest
```
With the following Env Vars:
| Variable | Value |
|----------|-------|
| `AWS_ACCESS_KEY_ID` | The access key from your provider |
| `AWS_SECRET_ACCESS_KEY` | The secret key from your provider |
::note
Generate these from your provider's dashboard, usually under something like "API keys" or "S3 credentials", scoped to that one bucket only if the provider allows it. There's no reason for a backup job's key to be able to touch anything else on your account.
::
### Repository maintenance (optional, but worth setting up once)
Back in the **Scheduling** tab, three policies keep a repository healthy over time. None of them are required to start backing up, restic works fine without ever touching them, but they're worth understanding once your repository has been running for a while:
:::collapsible{name="the three maintenance policies"}
- **Prune Policy**: deletes data that's no longer referenced by any snapshot (because old snapshots holding it were forgotten, see the retention policy in the next section). This is the only operation that actually frees up space on your storage. It's slow and reads a lot of data, so schedule it rarely, once a month is Backrest's own suggestion. **Max Unused After Prune** controls how thorough it is: a higher percentage leaves more unused data behind but finishes faster and copies less.
- **Check Policy**: verifies your repository isn't silently corrupted. **Read Data %** controls how much of the actual backed-up data gets re-read and checksummed, not just the repository's internal structure. 100% means a full re-read of everything, which uses real bandwidth and time; a smaller percentage checks a random sample instead. Once a month is, again, a reasonable default.
- **Forget Policy**: an optional repository-wide retention rule, applied across every plan writing to this repository instead of per-plan. Leave this disabled unless you specifically want one retention policy shared by multiple plans, it disables each plan's own retention policy the moment you turn it on.
Every one of these has a **Schedule Type**: `Disabled`, a plain `Interval` in hours or days, or a `Cron Expression` for anything more specific, plus a **Reference Clock** (your server's local time, UTC, or relative to the last time it ran) to anchor that schedule against.
:::
## Creating a backup plan
Back in Backrest, go to **Add Plan**. This form covers what to back up and when, as opposed to the repository form above, which only covers where:
- **Plan Name**: same rule as the repo name, pick something clear, you can't change it later.
- **Repository**: the one you just created above.
- **Paths**: click **Add** to add a row, then type in the container-side path for whatever you mounted above, it's a plain text field, but it autocompletes real paths from the container's filesystem as you type, handy to confirm a mount actually landed where you think. `/userdata/docker` for your stacks, `/userdata/etc` for your system config, `/userdata/home` for your own files. Click **Add** again for each additional folder, the small `-` button removes a row you don't need.
- **Excludes** and **Excludes (Case Insensitive)**: patterns to skip within those paths, handy for cache folders or anything genuinely disposable that would otherwise bloat every snapshot for no reason.
- **Schedule Type**: same three choices as the repository's own schedules above, `Disabled`, an `Interval`, or a `Cron Expression`. A nightly cron like `0 3 * * *` (every day at 3 AM) is a reasonable default for a homelab.
- **Retention Policy**: how many snapshots to keep, and for how long. **By Time Period** lets you say "keep 7 daily, 4 weekly, 6 monthly" independently, which gives you plenty of restore points spread over time without the repository growing forever, since restic deduplicates unchanged data between snapshots anyway. **By Count** instead just keeps the last N snapshots regardless of age. **Latest (Count)** on top of either mode guarantees a minimum number of recent snapshots always survive, whatever the rest of the policy says.
- **Advanced**: **Backup Flags** let you pass extra options straight to the underlying `restic backup` command for anything this form doesn't expose; **Hooks** run scripts or send notifications on backup events, the same mechanism as the repository's own Hooks tab, just scoped to this one plan instead of every plan using the repository.
That retention policy is your real defense against ransomware, by the way: if something starts encrypting your files at 2 AM, tonight's backup is compromised, but last week's snapshot isn't, and restic lets you restore from any of them.
::tip{icon="" to="/nonsense/bash/backrest-docker-stop"}
✨ __Going further:__ if some of what you're backing up includes a live database, stopping its container for the few seconds a backup takes is safer than backing it up while it's being written to. See **Backrest Docker Stop** for a script that does exactly that, triggered automatically by Backrest itself.
::
## Restoring a backup
A backup you've never tried restoring is a guess, not a plan, so it's worth doing once before you actually need it. Open the plan, click into a snapshot, expand **Snapshot Browser** down to whatever you need, then click the **...** menu next to it and pick **Restore to path**.
Leave the path field empty and Backrest streams it straight to your browser's downloads instead, the simplest option for grabbing a single file. Type a path and Backrest writes the restored data inside the container at that location instead, and it pre-fills a scratch folder like `/userdata-backrest-restore-<snapshot id>`, deliberately not your original mount.
That default isn't an accident: `/srv/docker`, `/etc` and `/home` are mounted `:ro`, so restic can't write back into them, restoring straight into `/userdata/docker` fails with a read-only filesystem error. Restore to that suggested scratch path (or download instead), check what you got, then copy the files into their real place yourself with `sudo cp -a`, from the host, outside of Backrest entirely. It's one extra step, but it also means a restore can never silently clobber live data by accident, exactly the caution you want mid-incident.
And that's it, you now have an actual backup strategy instead of a folder called `backup_final_v2_REAL`.
@@ -0,0 +1,169 @@
---
title: BTRFS Snapshots
description: 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](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.
## Installing Snapper
Rather than juggling raw `btrfs subvolume` commands by hand, [Snapper](https://github.com/openSUSE/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.
```bash [Terminal]
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`:
```properties [/etc/default/snapper]
SNAPPER_CONFIGS="root"
```
Then enable the timers that run Snapper's periodic snapshots and cleanup:
```bash [Terminal]
sudo systemctl enable --now snapper-timeline.timer snapper-cleanup.timer
```
`snapper-timeline.timer` fires **every hour** by default, that's fixed by the unit itself, not by a config option. Each run takes one snapshot and files it under the appropriate bucket (hourly, daily, monthly, yearly); the `TIMELINE_LIMIT_*` settings covered further down only control how many of each bucket survive, not how often a snapshot is taken. `snapper-cleanup.timer` runs once a day (plus once 10 minutes after boot) to enforce those limits.
::tip
✨ To take timeline snapshots at a different frequency, for example every 6 hours instead of every hour, override the timer instead of editing the package's unit file directly:
```bash [Terminal]
sudo systemctl edit snapper-timeline.timer
```
```ini [override.conf]
[Timer]
OnCalendar=
OnCalendar=*-*-* 0/6:00:00
```
The empty `OnCalendar=` line clears the packaged `hourly` value first, since systemd otherwise adds new `OnCalendar` lines to the existing ones instead of replacing them. Apply it with `sudo systemctl daemon-reload && sudo systemctl restart snapper-timeline.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:
```bash [Terminal]
sudo snapper create --description "before compose change on swag"
```
List every snapshot with:
```bash [Terminal]
sudo snapper list
```
```console [Output]
# | 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:
```bash [Terminal]
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:
```bash [Terminal]
sudo snapper status 1..0
```
That prints every file created, modified or deleted since. To undo those changes automatically:
```bash [Terminal]
sudo snapper undochange 1..0
```
Or restore a single file by hand, which is often the safer, more surgical choice:
```bash [Terminal]
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](/serveex/advanced/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:
```bash [Terminal]
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.
+1 -1
View File
@@ -43,7 +43,7 @@ Votre homelab à déployer, pas à pas
Scripts personnels et projets annexes Scripts personnels et projets annexes
:: ::
::card{icon="i-noto-recycling-symbol" title="Poubelle" to="/recycled/deprecated/wireguard-14"} ::card{icon="i-noto-recycling-symbol" title="Recyclage" to="/recycled/deprecated/wireguard-14"}
Pages périmées, conservées pour archive ou alternatives Pages périmées, conservées pour archive ou alternatives
:: ::
:: ::
+10
View File
@@ -296,6 +296,8 @@ ui:
icon: text-[#175DDC] icon: text-[#175DDC]
--- ---
Installer et déployer Vaultwarden Installer et déployer Vaultwarden
::
:: ::
:: ::
@@ -313,6 +315,14 @@ Installer et déployer Authentik
::card{icon="i-noto-crystal-ball" title="Gestionnaire Docker multi-hôtes" to="/serveex/advanced/arcane"} ::card{icon="i-noto-crystal-ball" title="Gestionnaire Docker multi-hôtes" to="/serveex/advanced/arcane"}
Installer et déployer Arcane Installer et déployer Arcane
:: ::
::card{icon="i-lucide-database-backup" title="Sauvegardes en 3-2-1" to="/serveex/advanced/backrest"}
Installer et déployer Backrest
::
::card{icon="i-lucide-rotate-ccw" title="Retour en arrière instantané" to="/serveex/advanced/btrfs-snapshots"}
Mettre en place les snapshots BTRFS
::
:: ::
## Bientôt ## Bientôt
@@ -89,6 +89,10 @@ Confirmez le fuseau horaire deviné à partir de votre pays.
*Assisté, utiliser un disque entier* sur le disque système, puis *Tout dans une seule partition*, ce qui vous donne un gros `/` plus une partition de swap. Des partitions `/home` ou `/var` séparées n'apportent pas grand-chose ici et garantissent surtout que l'une se remplit pendant que les autres restent à moitié vides. Ne prenez LVM que si vous savez déjà que vous voulez des snapshots ou agrandir des volumes plus tard. Vos disques de données ne sont pas touchés à ce stade, vous les monterez ensuite. *Assisté, utiliser un disque entier* sur le disque système, puis *Tout dans une seule partition*, ce qui vous donne un gros `/` plus une partition de swap. Des partitions `/home` ou `/var` séparées n'apportent pas grand-chose ici et garantissent surtout que l'une se remplit pendant que les autres restent à moitié vides. Ne prenez LVM que si vous savez déjà que vous voulez des snapshots ou agrandir des volumes plus tard. Vos disques de données ne sont pas touchés à ce stade, vous les monterez ensuite.
::warning{to="/serveex/advanced/btrfs-snapshots"}
__Pour les utilisateurs avancés :__ c'est maintenant qu'il faut décider, pas plus tard. Choisir *Manuel* ici plutôt qu'*Assisté* permet de formater la partition racine en Btrfs plutôt qu'en ext4, ce qui débloque des snapshots instantanés et quasi gratuits vers lesquels revenir avant une mise à jour risquée ou un changement de config. Une fois cette étape passée et Debian installé en ext4, passer à Btrfs n'est plus possible sans effacer le disque et tout recommencer. Voir **Snapshots BTRFS** pour la mise en place, ça ne remplace pas non plus de vraies sauvegardes, un snapshot vit sur le même disque.
::
Terminez avec *Terminer le partitionnement et appliquer les changements*, puis confirmez avec *Oui* : c'est le point de non-retour pour ce disque. Terminez avec *Terminer le partitionnement et appliquer les changements*, puis confirmez avec *Oui* : c'est le point de non-retour pour ce disque.
![Schéma de partitionnement de l'installateur Debian, tout dans une seule partition](/img/serveex/install/debian-install-partition.png) ![Schéma de partitionnement de l'installateur Debian, tout dans une seule partition](/img/serveex/install/debian-install-partition.png)
@@ -15,6 +15,8 @@ Nativement il gère une simple connexion locale identifiant/mot de passe, c'est
- [Documentation de TinyAuth](https://tinyauth.app/docs/getting-started) - [Documentation de TinyAuth](https://tinyauth.app/docs/getting-started)
- [TinyAuth sur GitHub](https://github.com/tinyauthapp/tinyauth) - [TinyAuth sur GitHub](https://github.com/tinyauthapp/tinyauth)
![Schéma de TinyAuth placé derrière SWAG en tant que proxy de forward-auth devant les services locaux](/img/serveex/tinyauth.svg)
## Installation ## Installation
::file-tree ::file-tree
@@ -15,6 +15,8 @@ C'est donc un bon choix si vous voulez simplement un backend SSO simple et rapid
- [Documentation de Pocket ID](https://pocket-id.org/docs) - [Documentation de Pocket ID](https://pocket-id.org/docs)
- [Pocket ID sur GitHub](https://github.com/pocket-id/pocket-id) - [Pocket ID sur GitHub](https://github.com/pocket-id/pocket-id)
![Schéma de Pocket ID agissant comme fournisseur d'identité OIDC natif derrière SWAG](/img/serveex/pocket-id-native.svg)
## Installation ## Installation
::file-tree ::file-tree
@@ -230,6 +232,8 @@ Enregistrez, puis copiez le __Client ID__ et le __Client Secret__ générés. Vo
## Connecter Pocket ID à TinyAuth ## Connecter Pocket ID à TinyAuth
[TinyAuth](/serveex/security/tinyauth) peut déléguer sa connexion à Pocket ID plutôt que (ou en plus de) son identifiant/mot de passe local, de sorte que quiconque visite une application protégée s'authentifie avec une passkey et se retrouve redirigé. [TinyAuth](/serveex/security/tinyauth) peut déléguer sa connexion à Pocket ID plutôt que (ou en plus de) son identifiant/mot de passe local, de sorte que quiconque visite une application protégée s'authentifie avec une passkey et se retrouve redirigé.
![Schéma de TinyAuth délégant la connexion à Pocket ID via OIDC](/img/serveex/pocket-id.svg)
::steps{level="3"} ::steps{level="3"}
### Enregistrer TinyAuth comme client OIDC ### Enregistrer TinyAuth comme client OIDC
@@ -0,0 +1,253 @@
---
title: Backrest
description: Installer Backrest, une interface web conviviale pour restic, et sauvegarder son serveur comme il faut avec la règle 3-2-1, vers un disque local, un autre serveur, S3 ou Backblaze B2.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
Soyons honnêtes deux secondes : la "stratégie de sauvegarde" de la plupart des homelabbers, c'est avoir copié quelques dossiers sur une clé USB une fois en 2019, et espérer que tout ira bien. [Backrest](https://github.com/garethgeorge/backrest) est là pour arranger ça, sans vous forcer à apprendre un outil en ligne de commande qui fait peur.
Sous le capot, Backrest est une interface web propre posée sur [restic](https://restic.net/), un moteur de sauvegarde open-source qui a fait ses preuves. Restic fait le vrai travail (chiffrer, dédupliquer, et envoyer vos données là où vous le lui dites) ; Backrest vous donne des boutons et des formulaires plutôt qu'un mur d'options à retenir.
![Tableau de bord de Backrest, montrant plusieurs dépôts et leur activité de sauvegarde récente](/img/serveex/backrest-dashboard.png)
## La règle du 3-2-1, ou pourquoi une seule sauvegarde n'en est pas une
Avant d'installer quoi que ce soit, parlons de la règle qui compte vraiment ici, parce qu'une sauvegarde mal pensée vous donne une fausse confiance, ce qui est pire que pas de sauvegarde du tout.
La **règle du 3-2-1** dit :
- **3** copies de vos données : l'originale, plus au moins deux sauvegardes.
- **2** types de stockage différents : pas deux copies sur le même disque, ni sur deux disques dans la même machine.
- **1** copie hors site : physiquement ailleurs, pas dans la même pièce, la même maison ou le même bâtiment que l'original.
Chaque chiffre ferme un scénario de panne précis :
- Une seule **(1)** sauvegarde ? Une seule erreur (un `rm -rf` malheureux, une restauration ratée, un fichier corrompu copié par-dessus le bon sans que vous le voyiez) peut emporter votre seul filet de sécurité en même temps que l'original.
- Des sauvegardes sur le **même type de stockage** (disons, un second disque interne dans le même serveur) ? Une surtension, un bug de firmware, ou une alimentation bas de gamme qui lâche peuvent très bien emporter tous les disques du boîtier d'un coup.
- Pas de copie **hors site** ? Un incendie, une inondation, un vol, ou "j'ai débranché la mauvaise multiprise" se moquent du nombre de disques que vous avez, s'ils sont tous dans la même pièce.
C'est aussi exactement pour ça que [le RAID n'est pas une sauvegarde](/general/storage/raid) : le RAID garde un service en marche quand un disque meurt, il ne fait rien contre un ransomware qui chiffre tous les fichiers qu'il peut atteindre, une suppression malheureuse, ou votre maison qui prend feu. Backrest, pointé vers une destination en dehors de votre serveur, est ce qui couvre réellement ces cas-là.
## Ce que Backrest sauvegarde, et où
Deux concepts à connaître avant de cliquer partout :
- Un **dépôt** (repository) est la destination : un espace de stockage chiffré et dédupliqué. C'est votre "2" et votre "1" de la règle ci-dessus, un disque externe, un autre serveur, ou du stockage cloud.
- Un **plan** est la règle que vous définissez : quels dossiers sauvegarder, vers quel dépôt, selon quel planning, et combien d'anciens instantanés (snapshots) conserver.
Vous pouvez avoir plusieurs plans sauvegardant vers plusieurs dépôts en même temps, ce qui est exactement comment on construit un vrai 3-2-1 : un plan vers un dépôt local pour des restaurations rapides, un autre plan vers un dépôt hors site pour le scénario "ma maison brûle".
## Installation
::file-tree
---
tree:
/:
- srv:
- docker:
- backrest:
- data/
- config/
- cache/
- compose.yaml
---
::
::steps{level="3"}
### Déployer la stack
Ouvrez Dockge, cliquez sur `compose`, nommez la stack `backrest`, et collez ce qui suit :
```yaml [compose.yaml]
---
services:
backrest:
image: garethgeorge/backrest:latest
container_name: backrest
restart: unless-stopped
ports:
- 9898:9898
volumes:
- ./data:/data
- ./config:/config
- ./cache:/cache
# Tout ce que vous voulez que Backrest puisse sauvegarder doit
# aussi être monté ici : la stack ne voit que ce qu'on lui donne.
- /srv/docker:/userdata/docker:ro
- /etc:/userdata/etc:ro
- /home:/userdata/home:ro
environment:
- BACKREST_DATA=/data
- BACKREST_CONFIG=/config/config.json
- XDG_CACHE_HOME=/cache
- TZ=Europe/Paris
```
Les lignes `/srv/docker`, `/etc` et `/home` ci-dessus couvrent ce qui vaut réellement la peine d'être sauvegardé hors site sur un serveur homelab, selon [dossiers et partitions](/general/linux/filesystem) : `/srv/docker` contient la config et les données de chaque stack (bases de données, fichiers uploadés, le coffre de Vaultwarden, les utilisateurs de Pocket ID, etc.), `/etc` contient votre configuration système (le durcissement SSH du [guide d'installation](/serveex/core/installation#refermer-la-porte-derrière-vous), vos fichiers `.subdomain.conf` de SWAG, les unités systemd), et `/home` contient vos propres scripts et notes. Les trois sont montées en lecture seule, un outil de sauvegarde n'a aucune raison d'écrire dans ce qu'il sauvegarde.
Ce qui ne vaut généralement **pas** le coup : une grosse bibliothèque média ou un dossier de téléchargement torrent sur un disque de données séparé. C'est souvent énorme, remplaçable, et rarement justifié de payer du stockage cloud ou de la bande passante SSH pour le protéger.
::tip{icon=""}
✨ __Astuce :__ ajoutez le label Watchtower pour automatiser les mises à jour
```yaml [compose.yaml]
services:
backrest:
#...
labels:
- com.centurylinklabs.watchtower.enable=true
```
::
Déployez le conteneur, puis ouvrez `http://ipdevotreserveur:9898`. La première visite vous demande de définir un identifiant et un mot de passe administrateur : faites-le immédiatement, Backrest n'a pas de compte par défaut et l'écran de configuration est grand ouvert tant que vous ne l'avez pas fait.
### Terminé !
::
## Créer votre premier dépôt
![Formulaire "Add Restic Repository" de Backrest, montrant une URI de dépôt Backblaze B2](/img/serveex/backrest.png)
Dans Backrest, allez dans **Add Repo**. Le formulaire est découpé en plusieurs sections, voici ce que fait chaque champ :
- **Repo Name** : ce qui vous aidera à le reconnaître plus tard, `cle-usb` ou `vps-hors-site` par exemple. Impossible de le renommer ensuite, choisissez quelque chose que vous ne regretterez pas.
- **Auto Unlock** : laissez désactivé sauf si vous comprenez bien ce que ça fait. Restic verrouille un dépôt pendant qu'il y travaille, pour qu'un second processus ne corrompe pas tout en écrivant en même temps. Auto Unlock retire ce verrou automatiquement au démarrage, pratique si Backrest a planté en pleine sauvegarde et laissé un verrou fantôme, mais réellement dangereux si deux machines écrivent un jour dans le même dépôt en même temps. Pour la configuration mono-serveur de cet article, c'est un confort mineur ; laissez désactivé en cas de doute.
- **Shared** : ne concerne que la fonctionnalité multihost de Backrest (plusieurs de vos machines gérant la même configuration de dépôt). Ignorez-le pour un serveur unique.
- **Repository URI** : là où les données vivent réellement. C'est ce champ qui change pour chaque destination ci-dessous.
- **Password** : le mot de passe de chiffrement de ce dépôt, cliquez sur **Generate** pour en générer un solide aléatoirement. **Conservez-le quelque part en dehors de ce serveur**, un gestionnaire de mots de passe, une note sur votre téléphone, n'importe où sauf un fichier texte posé à côté des sauvegardes qu'il protège. Perdez-le, et chaque sauvegarde devient un tas de bruit illisible et coûteux, sans exception, même pour les développeurs de restic.
- **Env Vars** : là où vous collerez les identifiants pour les destinations qui en ont besoin (S3 et B2 plus bas). Un disque local et le SFTP n'en ont besoin d'aucun.
::note
Les onglets **Scheduling**, **Hooks** et **Advanced** de ce formulaire configurent la maintenance du dépôt dans son ensemble (purge des anciennes données, vérification d'intégrité, notifications) plutôt que quoi que ce soit de spécifique à une destination. Ils sont couverts à la fin de cet article, une fois que vous avez un dépôt qui fonctionne réellement.
::
### Sauvegarder vers un disque local ou une clé USB
La copie hors site la plus simple qui soit est un disque que vous déplacez physiquement ailleurs après chaque sauvegarde, ou le disque d'une seconde machine joint par le réseau. Dans les deux cas, du point de vue de Backrest c'est juste un dossier, donc la configuration est identique : branchez le disque (ou montez le partage réseau) sur l'hôte, ajoutez-le aux volumes du fichier compose comme vous l'avez fait pour `/srv/docker` plus haut, puis dans le champ Repository URI, utilisez le chemin tel qu'il apparaît **à l'intérieur du conteneur** :
```text
/userdata/disque-sauvegarde
```
Voilà, aucun identifiant, aucune variable d'environnement. C'est aussi le dépôt le plus rapide pour restaurer, puisqu'il n'y a aucun aller-retour réseau, ce qui en fait un excellent choix pour votre copie de "récupération rapide", accompagnée d'une vraie copie hors site ci-dessous pour le scénario "ma maison brûle".
::caution
__Si ça ne marche pas :__ le chemin doit exister et être accessible en écriture par le conteneur avant de valider le formulaire. Un dossier vide convient très bien, restic initialise lui-même la structure du dépôt à la première utilisation.
::
### Sauvegarder vers un autre serveur
Pas de compte cloud, pas de problème : si vous avez un accès SSH à une autre machine, le serveur d'un ami, un petit VPS pas cher, un Raspberry Pi chez de la famille, c'est un dépôt hors site parfaitement valable, et ça ne coûte que ce que cette machine vous coûte déjà.
D'abord, assurez-vous que ce serveur peut se connecter en SSH à l'autre sans taper de mot de passe à chaque fois :
```bash [Terminal]
ssh-keygen -t ed25519 -f /srv/docker/backrest/config/id_ed25519 -N ""
ssh-copy-id -i /srv/docker/backrest/config/id_ed25519.pub votreutilisateur@lautreserveur
```
Montez cette clé dans le conteneur en l'ajoutant aux volumes du fichier compose :
```yaml [compose.yaml]
volumes:
# ...
- ./config/id_ed25519:/root/.ssh/id_ed25519:ro
```
Redéployez la stack, puis dans Backrest utilisez :
```text
sftp:votreutilisateur@lautreserveur:/chemin/vers/les/sauvegardes
```
::caution
__Si ça ne marche pas :__ le dossier cible (`/chemin/vers/les/sauvegardes` ci-dessus) doit déjà exister sur l'autre serveur, et cet utilisateur doit avoir le droit d'y écrire. Connectez-vous une fois à la main (`ssh votreutilisateur@lautreserveur`) pour confirmer que la connexion fonctionne et accepter la clé de l'hôte, Backrest tournant dans un conteneur n'aura pas l'invite interactive pour ça.
::
## Avancé : stockage objet dans le cloud
Un disque local ou le serveur de secours d'un ami couvre très bien la règle du 3-2-1, et ne coûte rien de plus que ce que vous possédez déjà. Le stockage objet dans le cloud est l'autre option classique, intéressante quand vous voulez une copie hors site qui ne dépend pas du matériel de quelqu'un d'autre restant allumé, pour un coût de quelques centimes à quelques euros par mois selon ce que vous sauvegardez.
### Backblaze B2
[Backblaze B2](https://www.backblaze.com/cloud-storage) est du stockage objet pensé exactement pour cet usage, et c'est généralement l'option la moins chère pour le schéma "on écrit souvent, on lit rarement" d'une sauvegarde.
Créez un bucket dans votre compte Backblaze, puis générez une **clé d'application** limitée à celui-ci. Dans Backrest, utilisez :
```text
b2:nom-de-votre-bucket:backrest
```
Avec les variables d'environnement suivantes :
| Variable | Valeur |
|----------|-------|
| `B2_ACCOUNT_ID` | L'identifiant de la clé d'application |
| `B2_ACCOUNT_KEY` | La clé d'application elle-même |
### Stockage compatible S3
S3 n'est pas juste un truc Amazon, c'est un protocole de stockage que la plupart des fournisseurs cloud parlent (OVH, Scaleway, MinIO si vous auto-hébergez le vôtre, et bien d'autres), ce qui en fait un choix solide et portable si vous préférez ne pas dépendre d'un fournisseur en particulier.
Créez un bucket chez le fournisseur de votre choix, puis dans le champ Repository URI de Backrest, utilisez :
```text
s3:https://s3.votre-fournisseur.com/nom-de-votre-bucket/backrest
```
Pour du vrai AWS S3, retirez le endpoint personnalisé :
```text
s3:s3.amazonaws.com/nom-de-votre-bucket/backrest
```
Avec les variables d'environnement suivantes :
| Variable | Valeur |
|----------|-------|
| `AWS_ACCESS_KEY_ID` | La clé d'accès de votre fournisseur |
| `AWS_SECRET_ACCESS_KEY` | La clé secrète de votre fournisseur |
::note
Générez ces clés depuis le tableau de bord de votre fournisseur, généralement sous un intitulé du genre "Clés API" ou "Identifiants S3", limitées à ce seul bucket si le fournisseur le permet. Il n'y a aucune raison que la clé d'un job de sauvegarde puisse toucher à autre chose sur votre compte.
::
### Maintenance du dépôt (optionnel, mais à mettre en place une fois pour toutes)
Retour dans l'onglet **Scheduling**, trois politiques gardent un dépôt en bonne santé dans le temps. Aucune n'est nécessaire pour commencer à sauvegarder, restic fonctionne très bien sans jamais y toucher, mais elles valent la peine d'être comprises une fois que votre dépôt tourne depuis un moment :
:::collapsible{name="les trois politiques de maintenance"}
- **Prune Policy** : supprime les données qui ne sont plus référencées par aucun instantané (parce que les anciens instantanés qui les contenaient ont été oubliés, voir la politique de rétention plus bas). C'est la seule opération qui libère réellement de l'espace sur votre stockage. C'est lent et ça lit beaucoup de données, donc planifiez-la rarement, une fois par mois est la suggestion de Backrest lui-même. **Max Unused After Prune** contrôle à quel point c'est minutieux : un pourcentage plus élevé laisse plus de données inutilisées derrière mais termine plus vite et copie moins.
- **Check Policy** : vérifie que votre dépôt n'est pas silencieusement corrompu. **Read Data %** contrôle quelle proportion des données réellement sauvegardées est relue et vérifiée par somme de contrôle, pas juste la structure interne du dépôt. 100% signifie relire l'intégralité du dépôt, ce qui consomme de la bande passante et du temps réels ; un pourcentage plus faible vérifie un échantillon aléatoire à la place. Une fois par mois est, encore une fois, un défaut raisonnable.
- **Forget Policy** : une règle de rétention optionnelle pour tout le dépôt, appliquée à travers tous les plans qui y écrivent au lieu d'être par plan. Laissez-la désactivée sauf si vous voulez spécifiquement une seule politique de rétention partagée par plusieurs plans, elle désactive la politique de rétention propre à chaque plan dès que vous l'activez.
Chacune de ces politiques a un **Schedule Type** : `Disabled`, un simple `Interval` en heures ou en jours, ou une `Cron Expression` pour quelque chose de plus précis, plus une **Reference Clock** (l'heure locale de votre serveur, UTC, ou relative à la dernière exécution) pour ancrer ce planning.
:::
## Créer un plan de sauvegarde
Retour dans Backrest, allez dans **Add Plan**. Ce formulaire couvre quoi sauvegarder et quand, contrairement au formulaire de dépôt ci-dessus, qui ne couvre que où :
- **Plan Name** : même règle que le nom du dépôt, choisissez quelque chose de clair, impossible à changer ensuite.
- **Repository** : celui que vous venez de créer plus haut.
- **Paths** : cliquez sur **Add** pour ajouter une ligne, puis tapez le chemin côté conteneur de ce que vous avez monté plus haut, c'est un champ texte, mais il autocomplète les vrais chemins du système de fichiers du conteneur au fur et à mesure, pratique pour confirmer qu'un montage a bien atterri là où vous pensez. `/userdata/docker` pour vos stacks, `/userdata/etc` pour votre config système, `/userdata/home` pour vos propres fichiers. Cliquez à nouveau sur **Add** pour chaque dossier supplémentaire, le petit bouton `-` retire une ligne dont vous n'avez plus besoin.
- **Excludes** et **Excludes (Case Insensitive)** : des motifs à ignorer au sein de ces chemins, pratique pour les dossiers de cache ou tout ce qui est vraiment jetable et qui gonflerait chaque instantané pour rien.
- **Schedule Type** : les trois mêmes choix que les plannings du dépôt ci-dessus, `Disabled`, un `Interval`, ou une `Cron Expression`. Un cron nocturne du type `0 3 * * *` (tous les jours à 3h du matin) est un défaut raisonnable pour un homelab.
- **Retention Policy** : combien d'instantanés conserver, et pendant combien de temps. **By Time Period** vous permet de dire "garder 7 quotidiens, 4 hebdomadaires, 6 mensuels" indépendamment, ce qui vous donne largement assez de points de restauration étalés dans le temps sans que le dépôt grossisse indéfiniment, puisque restic déduplique de toute façon les données inchangées entre les instantanés. **By Count** conserve à la place simplement les N derniers instantanés, quel que soit leur âge. **Latest (Count)** en plus de l'un ou l'autre mode garantit qu'un nombre minimum d'instantanés récents survit toujours, quoi que dise le reste de la politique.
- **Advanced** : **Backup Flags** vous permet de passer des options supplémentaires directement à la commande `restic backup` sous-jacente pour tout ce que ce formulaire n'expose pas ; **Hooks** exécute des scripts ou envoie des notifications sur les événements de sauvegarde, le même mécanisme que l'onglet Hooks du dépôt, mais limité à ce seul plan au lieu de tous les plans utilisant le dépôt.
Cette politique de rétention est d'ailleurs votre vraie défense contre les ransomwares : si quelque chose commence à chiffrer vos fichiers à 2h du matin, la sauvegarde de ce soir est compromise, mais celle de la semaine dernière ne l'est pas, et restic vous permet de restaurer depuis n'importe laquelle d'entre elles.
::tip{icon="" to="/nonsense/bash/backrest-docker-stop"}
✨ __Pour aller plus loin :__ si ce que vous sauvegardez inclut une base de données en cours d'exécution, arrêter son conteneur le temps des quelques secondes que prend la sauvegarde est plus sûr que de la sauvegarder pendant qu'elle écrit. Voir **Backrest Docker Stop** pour un script qui fait exactement ça, déclenché automatiquement par Backrest lui-même.
::
## Restaurer une sauvegarde
Une sauvegarde qu'on n'a jamais essayé de restaurer est un pari, pas un plan, ça vaut le coup de le faire une fois avant d'en avoir vraiment besoin. Ouvrez le plan, cliquez sur un instantané, dépliez **Snapshot Browser** jusqu'à ce dont vous avez besoin, puis cliquez sur le menu **...** à côté et choisissez **Restore to path**.
Laissez le champ de chemin vide et Backrest l'envoie directement vers les téléchargements de votre navigateur, l'option la plus simple pour récupérer un seul fichier. Tapez un chemin et Backrest écrit plutôt les données restaurées dans le conteneur à cet endroit, et il pré-remplit un dossier temporaire du type `/userdata-backrest-restore-<id du snapshot>`, volontairement pas votre montage d'origine.
Ce choix par défaut n'est pas un hasard : `/srv/docker`, `/etc` et `/home` sont montés en `:ro`, donc restic ne peut pas y réécrire, restaurer directement dans `/userdata/docker` échoue avec une erreur de système de fichiers en lecture seule. Restaurez vers ce dossier temporaire suggéré (ou téléchargez à la place), vérifiez ce que vous avez récupéré, puis recopiez les fichiers à leur vraie place vous-même avec `sudo cp -a`, depuis l'hôte, en dehors de Backrest. Une étape de plus, mais ça garantit aussi qu'une restauration ne peut jamais écraser silencieusement des données en cours d'utilisation, exactement la prudence qu'on veut en plein incident.
Et voilà, vous avez maintenant une vraie stratégie de sauvegarde plutôt qu'un dossier appelé `sauvegarde_finale_v2_LAVRAIE`.
@@ -0,0 +1,169 @@
---
title: Snapshots BTRFS
description: Formater la partition racine de Debian en BTRFS et utiliser Snapper pour annuler instantanément une mise à jour ratée ou un mauvais changement de config, en complément local des sauvegardes 3-2-1 hors site de Backrest.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
[BTRFS](https://btrfs.readthedocs.io/) est un système de fichiers Linux avec une fonctionnalité redoutable pour un homelab : les **snapshots**. Un snapshot fige l'état exact d'un système de fichiers en un instant, à coût quasi nul, sans copier le moindre octet de données au départ. Cassez quelque chose dix minutes après un `apt full-upgrade`, ou écrasez le mauvais fichier `.env`, et vous pouvez revenir exactement à l'état d'avant, sans toucher à une sauvegarde.
Ce n'est pas le rôle de [Backrest et de la règle 3-2-1](/serveex/advanced/backrest), donc autant être précis sur la différence avant de mettre quoi que ce soit en place.
## Un snapshot n'est pas une sauvegarde
Un snapshot vit sur le même disque que les données qu'il protège. Il est instantané, ne demande aucun réseau, et il est parfait pour annuler une bêtise que vous venez de faire, mais il ne sert strictement à rien le jour où ce disque lâche, se fait voler, ou où votre serveur part en fumée. C'est le rôle d'une vraie [sauvegarde 3-2-1](/serveex/advanced/backrest) : une copie sur un support différent, idéalement hors site.
Voyez ça comme ça :
- **Snapshot** = un bouton annuler. Instantané, local, gratuit, utile seulement tant que le disque est vivant.
- **Sauvegarde** = une assurance. Plus lente, hors site, la seule chose qui survit à la mort du disque lui-même.
Gardez les deux. Les snapshots vous rendent serein face aux mises à jour et aux expérimentations, les sauvegardes garantissent qu'un disque mort reste un désagrément plutôt qu'une catastrophe.
::note{to="/serveex/core/installation#partitionnement"}
Ce guide suppose que la partition racine a été formatée en Btrfs pendant [l'installation de Debian](/serveex/core/installation#partitionnement). Btrfs ne peut pas être ajouté proprement à un `/` déjà en ext4 après coup, c'est donc un choix à faire une seule fois, à l'installation.
::
## Formater la partition racine en BTRFS
Le partitionnement *Assisté* de Debian ne propose que de l'ext4. Pour obtenir du Btrfs, choisissez plutôt le partitionnement *Manuel*, à la même étape que décrit [le guide d'installation principal](/serveex/core/installation#partitionnement) :
::steps{level="3"}
### Sélectionner le partitionnement manuel
Sur l'écran de méthode de partitionnement, choisissez *Manuel* plutôt que *Assisté, utiliser un disque entier*.
### Créer une table de partitions
Sélectionnez le disque, confirmez la création d'une nouvelle table de partitions vide, puis sélectionnez l'*ESPACE LIBRE* obtenu et choisissez *Créer une nouvelle partition*.
### Définir la taille et le type de la partition
Donnez à la partition le reste du disque (moins une petite partition EFI si vous êtes en UEFI, gérée comme dans une installation Assistée), et réglez *Utiliser comme* sur __Système de fichiers journalisé Btrfs__, avec comme point de montage `/`.
### Terminer le partitionnement
*Terminer le partitionnement et appliquer les changements*, puis confirmez avec *Oui*.
### Terminé !
::
Tout le reste de [l'installeur](/serveex/core/installation#installer-debian) reste identique.
## Installer Snapper
Plutôt que de jongler à la main avec des commandes `btrfs subvolume` brutes, [Snapper](https://github.com/openSUSE/snapper) est un petit outil qui gère tout le cycle de vie des snapshots : les créer, les ranger proprement, supprimer les anciens, et encadrer automatiquement chaque opération `apt` d'une paire de snapshots.
```bash [Terminal]
sudo apt install snapper
sudo snapper -c root create-config /
```
`create-config` enregistre une configuration nommée `root` pour le système de fichiers `/`, et crée un sous-volume `.snapshots` dédié en dessous pour y stocker chaque snapshot, verrouillé pour root uniquement. Pas besoin de découpage `@`/`@home`, ça fonctionne très bien sur le layout à sous-volume unique que le partitionnement manuel vient de créer.
Activez la configuration en éditant `/etc/default/snapper` :
```properties [/etc/default/snapper]
SNAPPER_CONFIGS="root"
```
Puis activez les timers qui exécutent les snapshots périodiques et le nettoyage de Snapper :
```bash [Terminal]
sudo systemctl enable --now snapper-timeline.timer snapper-cleanup.timer
```
`snapper-timeline.timer` se déclenche **toutes les heures** par défaut, c'est fixé par l'unité elle-même, pas par une option de configuration. Chaque exécution prend un snapshot et le range dans la bonne catégorie (horaire, quotidien, mensuel, annuel) ; les réglages `TIMELINE_LIMIT_*` vus plus bas ne contrôlent que combien de snapshots de chaque catégorie survivent, pas la fréquence à laquelle ils sont pris. `snapper-cleanup.timer` tourne une fois par jour (plus une fois 10 minutes après le démarrage) pour appliquer ces limites.
::tip
✨ Pour prendre des snapshots de chronologie à une fréquence différente, par exemple toutes les 6 heures plutôt que toutes les heures, surchargez le timer plutôt que de modifier directement le fichier d'unité du paquet :
```bash [Terminal]
sudo systemctl edit snapper-timeline.timer
```
```ini [override.conf]
[Timer]
OnCalendar=
OnCalendar=*-*-* 0/6:00:00
```
La ligne `OnCalendar=` vide efface d'abord la valeur `hourly` du paquet, puisque systemd ajoute sinon les nouvelles lignes `OnCalendar` à celles déjà présentes au lieu de les remplacer. Appliquez avec `sudo systemctl daemon-reload && sudo systemctl restart snapper-timeline.timer`.
::
::note
Le paquet Debian embarque aussi un hook APT (`/etc/apt/apt.conf.d/80snapper`) qui s'active dès qu'une configuration figure dans `SNAPPER_CONFIGS` : à partir de maintenant, chaque `apt install`, `apt upgrade` ou `apt full-upgrade` obtient automatiquement un snapshot juste avant et juste après son exécution, sans aucun effort de votre part.
::
## Prendre un snapshot
Pour tout ce qui sort du cadre d'apt, comme modifier une unité systemd ou un fichier Docker Compose, prenez-en un vous-même avec une description qui voudra vraiment dire quelque chose plus tard :
```bash [Terminal]
sudo snapper create --description "avant changement compose sur swag"
```
Listez-les tous avec :
```bash [Terminal]
sudo snapper list
```
```console [Output]
# | Type | Pre # | Date | Description
---+--------+-------+--------------------------+---------------------------------
0 | single | | | current
1 | single | | Tue 09 Sep 2026 18:30:00 | avant changement compose sur 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
```
## Restaurer des fichiers depuis un snapshot
Snapper conserve l'état complet du système de fichiers au moment du snapshot sous `/.snapshots/<numéro>/snapshot`, consultable comme n'importe quel autre dossier :
```bash [Terminal]
ls /.snapshots/1/snapshot/etc/ssh/
```
Pour voir exactement ce qui a changé entre un snapshot et le système actuel (`0` désigne toujours "l'état actuel") avant de toucher à quoi que ce soit :
```bash [Terminal]
sudo snapper status 1..0
```
Ça affiche chaque fichier créé, modifié ou supprimé depuis. Pour annuler ces changements automatiquement :
```bash [Terminal]
sudo snapper undochange 1..0
```
Ou restaurez un seul fichier à la main, souvent le choix le plus sûr et le plus chirurgical :
```bash [Terminal]
sudo cp -a /.snapshots/1/snapshot/etc/ssh/sshd_config /etc/ssh/sshd_config
```
::note
Ça couvre l'immense majorité des vrais accidents de homelab : une mauvaise config, un fichier supprimé, une mise à jour de paquet qui a cassé un truc. Snapper peut aussi faire un `rollback` de toute la partition racine vers un snapshot antérieur (il crée un nouveau sous-volume par défaut et démarre dessus au prochain redémarrage), pour un système dans un état vraiment cassé plutôt qu'un simple fichier manquant. C'est une opération plus délicate et bien plus rare, à tester une fois sur une machine où redémarrer ne vous dérange pas, avant d'en avoir vraiment besoin. Et si le disque lui-même est le problème, c'est exactement le scénario pour lequel votre sauvegarde [Backrest](/serveex/advanced/backrest) hors site existe.
::
## Gérer et nettoyer les snapshots
Les snapshots sont bon marché, pas gratuits : dès que le système de fichiers actif diverge d'un snapshot, les anciens blocs qu'il référence toujours restent occupés. Sans surveillance, des mois de snapshots sur un serveur qui change beaucoup (images de conteneurs, logs) peuvent discrètement grignoter de l'espace disque réel.
Le `snapper-cleanup.timer` activé plus haut nettoie déjà automatiquement, selon la configuration de `/etc/snapper/configs/root` :
| Réglage | Défaut | Ce que ça fait |
|---------|---------|---------------|
| `TIMELINE_LIMIT_HOURLY` / `_DAILY` / `_MONTHLY` / `_YEARLY` | `10` | Combien de snapshots de chronologie garder pour chaque granularité |
| `TIMELINE_LIMIT_WEEKLY` | `0` | Désactivé par défaut |
| `NUMBER_LIMIT` | `50` | Combien de snapshots manuels (`single`) garder |
Ajustez ça à votre goût, puis supprimez-en un immédiatement à la main si vous avez besoin de la place tout de suite :
```bash [Terminal]
sudo snapper delete 1
```
Vérifiez l'usage disque réel avec `df -h /` : les chiffres ci-dessus ne plafonnent que le nombre de snapshots, pas l'espace qu'un serveur très actif peut encore consommer entre deux nettoyages.
Et voilà : un bouton annuler automatique et permanent pour votre serveur, qui encadre discrètement chaque mise à jour et se nettoie tout seul, en tournant à côté des vraies sauvegardes que Backrest prend déjà hors site.
+1 -1
View File
@@ -1,2 +1,2 @@
title: Poubelle title: Recyclage
icon: i-noto-recycling-symbol icon: i-noto-recycling-symbol
+1 -1
View File
@@ -1,5 +1,5 @@
--- ---
title: Recyclés title: Recyclage
description: Des tutoriels obsolètes gardés pour référence, et des applications alternatives remplacées ailleurs sur le site mais qui fonctionnent toujours très bien. description: Des tutoriels obsolètes gardés pour référence, et des applications alternatives remplacées ailleurs sur le site mais qui fonctionnent toujours très bien.
navigation: navigation:
icon: i-lucide-bookmark icon: i-lucide-bookmark
Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 51 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 80 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 141 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 30 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 68 KiB