server-up/docs/backups.md
Ramon ae99df2fc7
Some checks failed
Deploy server-up (dev) / deploy (push) Failing after 6s
v0.5.20-beta - complete backups en updates per app
Backups (core/backups.py, core/scheduler.py):
- Terugzetten met een klik: stack stoppen, huidige map opzij, uitpakken,
  starten. Mislukt het uitpakken, dan wordt de oude situatie teruggeplaatst.
- Bewaarbeleid: aantal per stack en/of maximale leeftijd; de nieuwste backup
  van een stack blijft altijd staan.
- Geplande backups (dagelijks/wekelijks) via een eigen planner in de app, geen
  cron. Een gemiste ronde loopt bij de eerstvolgende gelegenheid alsnog.
- Automatisch een backup voor het bijwerken of verwijderen van een stack.
  Mislukt die, dan gaat de actie door - anders kun je een kapotte stack niet
  meer opruimen.
- Uitpakken met tarfile + filter="data": absolute paden en ..-ingangen worden
  geweigerd. Met een kaal `tar xzf` kon een geprepareerd archief buiten de
  stackmap schrijven.
- Twee bugs in de oude implementatie: de returncode van tar werd genegeerd
  (mislukte backup gold als succes) en backups binnen dezelfde seconde
  overschreven elkaar.

Updates per app (core/stackupdates.py, core/registry.py):
- Badge op de stackkaart als er een nieuwer image is; bijwerken doet de
  bestaande update-knop.
- Vergelijking via de Registry API v2 (Docker-Content-Digest) in plaats van
  `docker manifest inspect`: dat laatste geeft per platform een aparte digest
  terwijl RepoDigests de manifest-list-digest bevat, wat bij elk multi-arch
  image permanent "update beschikbaar" zou opleveren.
- Drie statussen: update / current / unknown. Lokaal gebouwd, nog niet gepulld
  of registry onbereikbaar geeft unknown en dus geen badge.
- Dagelijkse achtergrondcheck, resultaten 6 uur gecached.

Verder:
- docs/backups.md, met nadruk op wat er niet in een backup zit: de
  Docker-volumes met de eigenlijke appdata.
- Backup-instellingen onder Instellingen; backup-geschiedenis per stack.
- 197 tests groen (40 nieuwe).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
2026-07-26 19:54:51 +02:00

138 lines
4.9 KiB
Markdown

# Backups
Server Up maakt backups van je stacks: handmatig, automatisch vóór risicovolle
acties, of op een schema. Terugzetten kan met één klik.
---
## ⚠️ Lees dit eerst: wat zit er wél en niet in
Een backup is een `.tar.gz` van de **stackmap** in je library. Daar zitten in:
- het compose-bestand
- het `.env`-bestand (met je wachtwoorden en tokens)
- eventuele configuratiebestanden die naast de compose staan
- `.serverup.json` met de metadata van de installatie
Wat er **niet** in zit: de Docker-volumes met de eigenlijke gegevens van de app.
| Voorbeeld | In de backup? |
|---|---|
| De compose van Vaultwarden | ✅ |
| Je `ADMIN_TOKEN` uit `.env` | ✅ |
| De wachtwoordkluis van Vaultwarden zelf | ❌ |
| De database van Paperless | ❌ |
| Je foto's in Immich | ❌ |
Je kunt hiermee dus een stack terugzetten zoals hij geconfigureerd stond, maar
niet de inhoud ervan herstellen. Wil je dat ook, dan zijn er twee routes:
1. **Bind mounts in plaats van named volumes.** Staat je data in
`/opt/serverup/appdata/<app>` en zit die map binnen je stackmap, dan gaat hij
wél mee. De meeste templates in `apps/` gebruiken `data_dir` daarvoor.
2. **Een aparte volume-backup** met bijvoorbeeld `restic` of `borg` naast Server
Up. Voor grote datasets is dat sowieso beter dan een tar per keer.
> Omdat een backup je `.env` bevat, staan er wachtwoorden in. `BACKUP_DIR` hoort
> dus dezelfde bescherming te hebben als de rest van `/data`.
---
## Een backup maken
**Per stack** — de archiefknop op de stackkaart maakt er direct een. De
geschiedenisknop ernaast toont alle backups van die stack, met de mogelijkheid
om terug te zetten of te verwijderen.
**Automatisch vóór risicovolle acties** — standaard aan voor:
- **bijwerken** van een stack (`compose pull` + `up`), want een nieuwe
image-versie kan een compose-wijziging nodig hebben;
- **verwijderen** van een stack, maar alleen als je "verwijder ook de bestanden"
kiest — bij het enkel stoppen van containers valt er niets te verliezen.
Uit te zetten onder **Instellingen → Backups**. Mislukt zo'n automatische
backup, dan gaat de actie alsnog door: anders zou je een kapotte stack niet meer
kunnen opruimen. De melding komt wel in het joblog.
**Gepland** — dagelijks of wekelijks, rond een uur dat je zelf kiest. De
planner draait in de applicatie zelf (geen cron nodig) en onthoudt in
`config.json` wanneer hij voor het laatst gelopen heeft. Stond de server uit op
het geplande moment, dan loopt de backup bij de eerstvolgende gelegenheid alsnog.
---
## Bewaarbeleid
Twee regels, die allebei tegelijk gelden:
| Instelling | Betekenis |
|---|---|
| `BACKUP_KEEP` | Hoeveel backups per stack je bewaart. `0` = onbeperkt. |
| `BACKUP_MAX_AGE_DAYS` | Alles ouder dan dit aantal dagen gaat weg. `0` = geen limiet. |
**De nieuwste backup van een stack blijft altijd staan**, ook als hij ouder is
dan de maximale leeftijd. Anders sta je na een lange vakantie met lege handen.
Opruimen gebeurt na elke nieuwe backup van die stack, en na een geplande ronde.
---
## Terugzetten
De geschiedenisknop op de stackkaart → **Terugzetten**. Wat er dan gebeurt:
```
1. docker compose down stack stoppen
2. huidige map opzij zetten als <stack>.restore-<tijdstempel>
3. archief uitpakken
4. opzijgezette map weggooien
5. docker compose up -d stack starten
```
Gaat stap 3 mis — een beschadigd archief, of een archief dat buiten de stackmap
probeert te schrijven — dan wordt de opzijgezette map teruggeplaatst. Je raakt
je stack dus niet kwijt aan een kapotte backup.
Een backup van stack A kun je niet over stack B heen zetten; dat wordt geweigerd
op basis van de metadata.
### Veiligheid
Archieven worden uitgepakt met Pythons `tarfile` en `filter="data"`. Dat weigert
absolute paden, `..`-ingangen, symlinks die buiten de map wijzen en
apparaatbestanden. Met een kaal `tar xzf` zou een geprepareerd archief bestanden
elders op de host kunnen neerzetten.
---
## Instellingen
| Sleutel | Standaard | Betekenis |
|---|---|---|
| `BACKUP_DIR` | `/opt/serverup/backups` | Waar de archieven komen |
| `BACKUP_KEEP` | `5` | Aantal per stack |
| `BACKUP_MAX_AGE_DAYS` | `0` | Maximale leeftijd in dagen |
| `BACKUP_SCHEDULE` | `off` | `off` / `daily` / `weekly` |
| `BACKUP_SCHEDULE_HOUR` | `3` | Rond welk uur de geplande ronde draait |
| `BACKUP_BEFORE_UPDATE` | `true` | Backup vóór het bijwerken van een stack |
| `BACKUP_BEFORE_REMOVE` | `true` | Backup vóór het verwijderen van bestanden |
---
## Handmatig
De archieven zijn gewone tarballs — je hebt Server Up niet nodig om erbij te
kunnen:
```bash
# Bekijken wat erin zit
tar tzf /opt/serverup/backups/vaultwarden_20260726_030000.tar.gz
# Ergens anders uitpakken
tar xzf /opt/serverup/backups/vaultwarden_20260726_030000.tar.gz -C /tmp/herstel
```
Naast elk archief staat een `.json` met de stacknaam, het tijdstip, de grootte
en de reden (handmatig, gepland, voor-update, voor-remove). Ontbreekt dat
bestand, dan leidt Server Up de gegevens af uit de bestandsnaam.