fix: Server-Daten in Named Volume statt Bind-Mount

./data war ein Bind-Mount relativ zum Git-Checkout - bei Dokploy wird
das Repo pro Deploy frisch geklont, ein per CLI angelegter Nutzer war
nach einem reinen Routing-Redeploy spurlos verschwunden. Betraf nicht
nur Nutzer, sondern denselben Api:DataPath für Ereignis-Log/Snapshots/
Anhänge - also jeden Server-Datenbestand bei jedem Redeploy.

- docker-compose.yml: Named Volume "api-data" statt Bind-Mount, lebt
  unabhängig vom Checkout im Docker-Daemon.
- backup.sh: auf volume-basiertes Backup umgeschrieben (Alpine-
  Hilfscontainer statt direktem Host-Pfad).
- docker/README.md, TODO.md 10.2.4: Vorfall dokumentiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 00:02:56 +02:00
co-authored by Claude Sonnet 5
parent a68bb933c5
commit cdac335ad1
4 changed files with 63 additions and 19 deletions
+22 -10
View File
@@ -7,8 +7,11 @@ cd docker
JWT_SECRET=<zufälliger-langer-string> docker compose up -d
```
`./data` (relativ zu `docker/`) wird als Volume gemountet und enthält alle Server-Daten
(Ereignis-Logs, Snapshots, Nutzer) bei Neustarts/Updates bleibt es erhalten.
Alle Server-Daten (Ereignis-Logs, Snapshots, Anhänge, Nutzer) liegen im Named Volume `api-data`
bei Neustarts/Updates bleibt es erhalten. Bewusst **kein** Bind-Mount auf einen Host-Pfad: bei
Git-basierten Deployments (z. B. Dokploy) wird das Checkout-Verzeichnis bei jedem Redeploy neu
geklont, ein dort liegendes `./data` wäre dabei jedes Mal leer (siehe TODO.md 10.2.4 für den
Vorfall, der das aufgedeckt hat).
## Nutzer anlegen
@@ -41,18 +44,27 @@ docker compose exec api dotnet LehrerApp.Api.dll set-password <benutzername> --p
## Backup
`backup.sh` sichert `./data` (Ereignis-Logs, Snapshots, Anhänge, Nutzer) als komprimiertes
Tar-Archiv unter `docker/backups/` und räumt Archive älter als 30 Tage automatisch auf. Läuft
direkt auf dem Host (kein Container-Zugriff nötig, `./data` liegt dort per Bind-Mount ohnehin):
`backup.sh` sichert das Named Volume `api-data` (Ereignis-Logs, Snapshots, Anhänge, Nutzer) über
einen kurzlebigen Alpine-Container als komprimiertes Tar-Archiv unter `docker/backups/` und räumt
Archive älter als 30 Tage automatisch auf:
```bash
./docker/backup.sh
```
Der volle Docker-Volume-Name ist `<compose-projektname>_api-data`. Lokal (`cd docker && docker
compose up`) ist das `docker_api-data` (Default im Skript), bei Dokploy der App-Slug, z. B.
`lehrerapp-syncserver-xyz_api-data` im Zweifel prüfen mit `docker volume ls | grep api-data`
und per Umgebungsvariable übergeben:
```bash
LEHRERAPP_DATA_VOLUME=lehrerapp-syncserver-xyz_api-data ./docker/backup.sh
```
Für regelmäßige Sicherung z. B. per Cron, einmal täglich nachts:
```bash
0 3 * * * /pfad/zu/docker/backup.sh >> /pfad/zu/docker/backup.log 2>&1
0 3 * * * LEHRERAPP_DATA_VOLUME=... /pfad/zu/docker/backup.sh >> /pfad/zu/docker/backup.log 2>&1
```
## Rate Limiting
@@ -82,7 +94,7 @@ selbst aus `docker/Dockerfile.api`.
6. **Nutzer anlegen** nach dem ersten Deploy: über Dokploys Terminal/Exec-Tab am laufenden
Container `dotnet LehrerApp.Api.dll create-user <name>` ausführen (siehe oben).
Der `./data`-Bind-Mount bleibt unverändert Dokploy hält das Checkout-Verzeichnis der
Compose-App über Redeploys hinweg stabil, `backup.sh` funktioniert damit unverändert weiter.
Nach dem ersten echten Deploy einmal gegenprüfen: Redeploy anstoßen und verifizieren, dass
Daten (z. B. ein testweise angelegter Nutzer) erhalten bleiben.
**Wichtig:** die Daten liegen im Named Volume `api-data`, nicht in einem Bind-Mount Dokploy
klont das Repo bei jedem Redeploy neu, ein Bind-Mount relativ zum Checkout wäre dabei jedes Mal
leer gewesen (das ist real passiert, siehe TODO.md 10.2.4). Named Volumes übersteht Dokploys
`docker compose up --build --remove-orphans` dagegen unverändert.