feat(ops): Automatisches Backup (DB + Dateien, 30 Tage) (v1.8.11)
Schliesst den offenen Punkt: die Datenschutzerklärung nannte "bis zu 30 Tage", real fehlte ein Backup. - Neuer backup-Container (postgres:16-alpine) in docker-compose.yml und deploy/portainer-stack.yml: täglich pg_dump (custom/komprimiert) + tar der MinIO-Dateien, Prune > 30 Tage, im Volume backups_data - Konfigurierbar: BACKUP_RETENTION_DAYS, BACKUP_INTERVAL_HOURS (.env.example ergänzt) - scripts/restore.sh + docs/BACKUP.md (Einrichtung, Off-Site-Hinweis, Restore DB+Dateien, Restore-Test-Tabelle) - TOM-Doku aktualisiert (Backup vorhanden) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
82
docs/BACKUP.md
Normal file
82
docs/BACKUP.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Backup & Restore — Lageplan
|
||||
|
||||
Automatisches Backup als eigener Container (`backup`). Sichert **täglich**:
|
||||
- **Datenbank** (PostgreSQL) → `db_<zeitstempel>.dump` (pg_dump, custom/komprimiert)
|
||||
- **Hochgeladene Dateien** (MinIO: Pläne, Logos, Symbole) → `files_<zeitstempel>.tar.gz`
|
||||
|
||||
**Aufbewahrung:** 30 Tage (ältere werden automatisch gelöscht) — passt zur Datenschutzerklärung.
|
||||
Einstellbar über `BACKUP_RETENTION_DAYS` und `BACKUP_INTERVAL_HOURS` (siehe `.env.example`).
|
||||
|
||||
Die Backups liegen im Docker-Volume **`backups_data`** (Pfad im Container: `/backups`).
|
||||
|
||||
---
|
||||
|
||||
## Einrichtung
|
||||
|
||||
Der `backup`-Service ist in `docker-compose.yml` und `deploy/portainer-stack.yml` enthalten.
|
||||
Nach dem nächsten Stack-Update (Portainer: Stack neu deployen) läuft er automatisch.
|
||||
|
||||
Prüfen, dass er läuft und sichert:
|
||||
```
|
||||
docker logs lageplan-backup # oder: docker compose logs backup
|
||||
docker compose exec backup ls -lh /backups
|
||||
```
|
||||
Beim ersten Start wird sofort ein Backup erstellt, danach alle 24 h.
|
||||
|
||||
### Empfehlung: Backups aus dem Container heraus auf den NAS legen (Off-Site)
|
||||
Standardmässig liegen die Backups in einem Docker-Volume. Damit sie ausserhalb von Docker
|
||||
(z. B. auf einer NAS-Freigabe, die du separat sicherst) landen, im Stack den `backup`-Service auf
|
||||
einen **Host-Pfad** umstellen:
|
||||
```yaml
|
||||
volumes:
|
||||
- /volume1/backups/lageplan:/backups # statt backups_data:/backups
|
||||
- minio_data:/minio:ro
|
||||
```
|
||||
So kannst du die Dateien einfach kopieren/auf ein anderes Medium spiegeln. **Wichtig:** Ein Backup
|
||||
auf demselben Gerät wie die Daten schützt nicht vor Geräteausfall/Diebstahl — kopiere die Backups
|
||||
regelmässig an einen zweiten Ort.
|
||||
|
||||
---
|
||||
|
||||
## Wiederherstellen (Restore)
|
||||
|
||||
> **Destruktiv.** Vorher die Web-App stoppen (`docker stop lageplan-web`) und sicherstellen, dass
|
||||
> niemand arbeitet.
|
||||
|
||||
### 1) Datenbank
|
||||
```
|
||||
# Verfügbare Dumps anzeigen
|
||||
docker compose exec backup ls -lh /backups
|
||||
|
||||
# Wiederherstellen (Dateiname einsetzen)
|
||||
docker compose exec backup pg_restore --clean --if-exists --no-owner \
|
||||
-h db -U <POSTGRES_USER> -d <POSTGRES_DB> /backups/db_2026-07-23_030000.dump
|
||||
```
|
||||
|
||||
### 2) Dateien (Uploads/MinIO)
|
||||
Da `/minio` im backup-Container schreibgeschützt ist, den Tarball in einen Container mit
|
||||
Schreibzugriff auf das MinIO-Volume entpacken:
|
||||
```
|
||||
docker run --rm -v minio_data:/data -v backups_data:/backups alpine \
|
||||
sh -c "tar xzf /backups/files_2026-07-23_030000.tar.gz -C /data"
|
||||
```
|
||||
Danach Web-App wieder starten: `docker start lageplan-web`.
|
||||
|
||||
---
|
||||
|
||||
## Restore-Test (mindestens 1× durchführen und hier notieren)
|
||||
|
||||
Ein Backup ist erst dann ein Backup, wenn ein Restore nachweislich funktioniert.
|
||||
Empfehlung: **halbjährlich** auf einer Testumgebung durchspielen.
|
||||
|
||||
| Datum | Getestet von | Ergebnis | Bemerkung |
|
||||
|-------|--------------|----------|-----------|
|
||||
| | | | |
|
||||
|
||||
---
|
||||
|
||||
## Was ist NICHT im Backup?
|
||||
- Zahlungsdaten liegen bei Stripe (nicht in der App).
|
||||
- E-Mails liegen beim SMTP-Anbieter.
|
||||
- Secrets (`NEXTAUTH_SECRET`, MinIO-Keys) — separat sicher aufbewahren (Passwort-Manager),
|
||||
sie stehen nicht in den Backups.
|
||||
@@ -36,8 +36,10 @@ Legende: ✅ vorhanden · ⚠️ teilweise / zu bestätigen · ❌ offen / nicht
|
||||
- ⚠️ Secrets-Verwaltung: ENV (`NEXTAUTH_SECRET`, MinIO) + DB (`SystemSetting`: SMTP/Stripe) → **Absicherung der DB-Secrets bestätigen**.
|
||||
|
||||
## Backup & Wiederherstellung
|
||||
- ⚠️ Backups: `[VORHANDEN? FREQUENZ? AUFBEWAHRUNG?]` (siehe `docs/backup-und-seeding.md`).
|
||||
- ❌ Restore-Tests: `[DOKUMENTIEREN]`.
|
||||
- ✅ Automatisches Backup (eigener `backup`-Container): täglich Postgres-Dump + MinIO-Dateien,
|
||||
30 Tage Aufbewahrung (`docker-compose.yml` / `deploy/portainer-stack.yml`, Anleitung `docs/BACKUP.md`).
|
||||
- ⚠️ Off-Site-Kopie: empfohlen (Backups zusätzlich an einen zweiten Ort spiegeln) — siehe `docs/BACKUP.md`.
|
||||
- ⚠️ Restore-Test: mindestens 1× durchführen und in `docs/BACKUP.md` protokollieren.
|
||||
|
||||
## Logging & Monitoring
|
||||
- ✅ Server-Logs (console). ⚠️ Vermeidung sensibler Daten in Logs → **Review empfohlen**.
|
||||
|
||||
Reference in New Issue
Block a user