diff --git a/ops/borg-ui/BACKUP_AUDIT_STATUS_QUO.md b/ops/borg-ui/BACKUP_AUDIT_STATUS_QUO.md new file mode 100644 index 0000000..2b1d997 --- /dev/null +++ b/ops/borg-ui/BACKUP_AUDIT_STATUS_QUO.md @@ -0,0 +1,264 @@ +# Backup Audit - Status Quo + +Stand: 2026-04-15 + +Dieses Dokument beschreibt den aktuellen Ist-Zustand des Homelab-Backups, bevor weitere Strukturänderungen oder Migrationsschritte vorgenommen werden. + +## Ziel dieses Audits + +1. Festhalten, welche Daten wo liegen. +2. Prüfen, was aktuell im Borg-Scope enthalten ist. +3. Sichtbar machen, welche Lücken oder Unsicherheiten noch bestehen. +4. Erst danach über Umzüge oder Bereinigungen entscheiden. + +## Shares - fachliche Einordnung + +| Share | Aktuelle Rolle | Bewertung | +| --- | --- | --- | +| `appdata` | App-Konfig, Datenbanken, App-State, Secrets | fachlich normal, aber gemischt; nicht alles daraus sollte pauschal gebackupt werden | +| `documents` | Nutzdaten für Dokumente / Paperless | fachlich sauber | +| `photos` | Nutzdaten für Bilder / Immich / Archiv | fachlich sauber | +| `services` | GitOps / Infrastruktur / Gitea / Compose | fachlich sauber | +| `backups` | Backup-Ziele und Restore-Daten | sollte frei von Live-App-Daten bleiben | +| `media` | Mediathek / große Inhaltsdaten | aktuell nicht Teil des Critical-Scopes | +| `finance` | sensible Nutzdaten | aktuell nicht Teil des Critical-Scope | +| `projekte` | Projekt- und Entwicklungsdaten | aktuell nicht Teil des Critical-Scope | + +## Aktueller Borg-Zielzustand + +Es gibt derzeit zwei relevante Ebenen: + +1. Ein älteres breites Test-Repository (`hetzner_borg-appdata`), das nicht als finales Design gewertet werden sollte. +2. Ein neues gezieltes Critical-Repository (`critical_infra`), das den fachlich wichtigen Scope abdecken soll. + +Der technische Scope für `critical_infra` ist in `all-important-sources.txt` festgehalten. + +## Aktueller Borg-Scope - Quellen + +### Dumps + +- `/local/borg-dumps` + +### Kritische App-/Nutzdaten + +- `/local/appdata/vaultwarden` +- `/local/appdata/paperless-ngx/data` +- `/local/paperless/media` +- `/local/paperless/export` +- `/local/paperless/consume` +- `/local/immich/upload` +- `/local/immich/external` +- `/local/gitea/data` +- `/local/appdata/mealie/data` +- `/local/appdata/firefly/upload` +- `/local/appdata/mailarchiver/data-protection-keys` + +### Secrets / Konfiguration / Infrastruktur + +- `/local/secrets` +- `/local/appdata/authelia/config` +- `/local/appdata/traefik` +- `/local/appdata/homepage` +- `/local/appdata/ntfy` +- `/local/appdata/paperless-gpt` +- `/local/appdata/tailscale` +- `/local/appdata/adguard/conf` +- `/local/appdata/borg-ui/data` +- `/local/appdata/komodo/periphery` +- `/local/appdata/komodo/core` + +## Service-Audit + +| Service | Nutzdaten | DB / technischer Zustand | Aktuell durch Borg abgedeckt? | Bewertung | +| --- | --- | --- | --- | --- | +| Vaultwarden | `/mnt/user/appdata/vaultwarden` | Datei-basiert | Ja | gut | +| Paperless | `documents` + `appdata/paperless-ngx/data` | Shared PostgreSQL Dump vorhanden | Ja | gut | +| Immich | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive` | eigener PostgreSQL Dump vorhanden | Ja | gut | +| Gitea | `/mnt/user/services/gitea/data` | SQLite in `/data` | Ja | gut | +| Mealie | `/mnt/user/appdata/mealie/data` | eigener PostgreSQL Dump vorhanden | Ja | gut | +| Mail-archiver | DataProtection-Keys | Shared PostgreSQL Dump vorhanden | Ja | gut | +| Authelia | Config + Secrets | Shared PostgreSQL Dump vorgesehen / erzeugt | Ja | gut | +| Traefik | dynamische Config + Let's Encrypt | keine separate DB | Ja | gut | +| Homepage | Config + Bilder | keine separate DB | Ja | gut | +| ntfy | Datei-Daten | keine separate DB | Ja | gut | +| Paperless-GPT | lokale Daten / Prompts | keine separate DB | Ja | gut | +| Tailscale | State-Verzeichnis | keine separate DB | Ja | gut | +| AdGuard | `conf` | `work` bewusst nicht im Critical-Scope | Teilweise | okay | +| Komodo | `core` + `periphery` | MongoDB Dump aktuell nicht verifiziert | Teilweise | offen | +| Firefly | Uploads | MariaDB Dump scheitert aktuell an korruptem Table | Teilweise | offen, aber niedrige Priorität wenn Ablösung geplant | +| Semaphore | Docker named volumes | Shared PostgreSQL vorgesehen, App-Volumes nicht in Borg | Nein / Teilweise | Lücke | +| Redis | transiente Daten / Cache | absichtlich nicht im Scope | Nein | bewusst ausgeschlossen | +| Scrutiny | Config + InfluxDB | InfluxDB nicht im Scope | Nein | bewusst ausgeschlossen | +| Plex | Medien-Metadaten / Cache | kein Critical-Scope | Nein | bewusst ausgeschlossen | + +## Datenbank-Dumps - Ist-Zustand + +### Erfolgreich erzeugt + +- `postgresql17-globals.sql` +- `postgresql17-mailarchiver.dump` +- `postgresql17-paperless.dump` +- `postgresql17-semaphore.dump` +- `postgresql17-authelia.dump` +- `mealie.dump` +- `immich.dump` + +### Nicht erfolgreich / nicht bestätigt + +- `firefly.sql` - Dump scheitert aktuell an korruptem MariaDB-Table `rt_meta` +- `komodo-mongo.archive.gz` - im bisherigen Lauf nicht sichtbar, daher noch nicht als bestätigt werten + +## Ergebnis des ersten `critical_infra`-Laufs + +Der erste vollständige Lauf des neuen Borg-Repositories `critical_infra` wurde erfolgreich abgeschlossen. + +### Bestätigter Lauf + +- Repository: `ssh://u565255@u565255.your-storagebox.de:23/./hetzner_borg_appdata_critical` +- Archiv: `manual-backup-2026-04-13T19:19:52` +- Status: erfolgreich (`rc 0`) +- Laufzeit: `1h 37m 12s` +- Dateien: `63.237` +- Archivgröße: `24,73 GB` original / `24,53 GB` komprimiert / `23,37 GB` dedupliziert + +### Bedeutung + +Damit ist bestätigt, dass der aktuelle Critical-Scope technisch durch Borg gesichert werden kann. + +Das betrifft insbesondere: + +- Paperless-Dokumente und zugehörige Dumps +- Immich-Uploads und `photos/family_archive` +- Gitea-Daten +- Vaultwarden +- Secrets / Traefik / Authelia +- die aktuell erzeugten PostgreSQL-Dumps + +### Weiterhin offen trotz erfolgreichem Lauf + +- `komodo-mongo`-Dump bleibt unbestätigt +- Dump-Automatisierung vor dem Borg-Lauf fehlt noch +- der Scope kann später noch bewusst verschlankt werden, ist aber aktuell funktionsfähig + +## Was aktuell bewusst nicht als Problem gewertet wird + +- `photos/family_archive` liegt fachlich korrekt im Share `photos` und wird durch Borg gesichert. +- Paperless liegt absichtlich über mehrere Shares verteilt: + - `documents` für Nutzdaten + - `appdata` für App-State + - Dump für DB +- Immich liegt absichtlich über mehrere Bereiche verteilt: + - `photos` für Bilder + - `appdata` für DB + - Dump für DB + +Das ist kein Strukturfehler, sondern eine normale Trennung zwischen Nutzdaten und App-State. + +## Aktuelle Lücken / offene Entscheidungen + +1. **Komodo MongoDB** + - Dump-Pfad im Skript vorhanden + - Erfolg noch nicht bestätigt + +2. **Semaphore** + - PostgreSQL-Teil ist grundsätzlich dumpbar + - die App selbst nutzt aber Docker named volumes + - diese Volumes sind aktuell nicht sauber im Borg-Scope enthalten + +3. **Firefly** + - Datei-Uploads sind enthalten + - DB-Dump aktuell fehlerhaft + - wenn Firefly sowieso bald entfernt wird, ist das momentan nicht blockierend + +4. **Automatisierung** + - Dumps wurden manuell erzeugt + - die festgelegte Zielrichtung ist jetzt host-seitig über Unraid User Scripts / Host-Cron + - eine saubere Pre-Backup-Automatisierung ist noch nicht final eingebunden + +## Vorläufiges Audit-Fazit + +Der aktuelle Borg-Scope ist **nicht chaotisch**, sondern bereits deutlich strukturierter als ein pauschales Backup von `/mnt/user/appdata`. + +Fachlich sieht das Bild aktuell so aus: + +- `appdata` = technischer App-State +- `documents` = Paperless-/Dokumenten-Nutzdaten +- `photos` = Immich-/Bild-Nutzdaten +- `services` = GitOps / Gitea / Infra +- `backups` = Backup-Ziel, nicht Live-Daten + +Das eigentliche Restproblem ist aktuell **nicht** die Share-Struktur, sondern: + +- einzelne noch offene Dump-Kandidaten +- fehlende Automatisierung +- einzelne Spezialfälle wie Semaphore named volumes + +## Nächste sinnvolle Schritte + +1. Den erfolgreichen ersten `critical_infra`-Lauf als bestätigt festhalten und nur die verbleibenden Restpunkte weiterverfolgen. +2. Die offenen Restpunkte gegen den Audit halten: + - `komodo-mongo` weiterhin als unbestätigt markieren + - Dump-Automatisierung als nächsten echten Umsetzungsblock behandeln + - dafür host-seitig über Unraid User Scripts / Host-Cron arbeiten, nicht über Borg-UI-Inline-Hooks + - optionale spätere Scope-Verschlankung nur bewusst und nicht ad hoc vornehmen +3. Erst danach entscheiden: + - ob Pfade umgezogen werden müssen + - ob Firefly schlicht ausläuft statt weiter bereinigt zu werden + - wie die Pre-Backup-Dumps automatisiert werden + +## Festgehaltene Entscheidung + +Stand jetzt werden **keine grundlegenden Share-Umstrukturierungen** vorgenommen. + +### Begründung + +- Die aktuelle Share-Struktur ist fachlich grundsätzlich brauchbar: + - `appdata` = technischer App-State + - `documents` = Dokument-Nutzdaten + - `photos` = Bild-/Immich-Nutzdaten + - `services` = GitOps / Infrastruktur + - `backups` = Backup-Ziel +- Der erwartete Ertrag eines großen Share-Umbaus ist aktuell niedrig. +- Das Risiko eines Umbaus ist vergleichsweise hoch, weil Live-Pfade, Compose-Mounts und Backup-Quellen gleichzeitig betroffen wären. +- Der aktuelle Engpass liegt nicht in den Shares selbst, sondern in: + - vollständiger Borg-Abdeckung + - sauberer Dump-Automatisierung + - einzelnen offenen Spezialfällen + +### Spezifische Bewertung + +- `photos/family_archive` bleibt an Ort und Stelle. +- `documents`-Pfade für Paperless bleiben an Ort und Stelle. +- `services/gitea` bleibt an Ort und Stelle. +- `appdata` wird aktuell nicht großflächig bereinigt oder umgebaut. + +### Einfluss von Firefly und Semaphore + +- `Semaphore` ist als zukünftige Löschung eingeplant und wird deshalb **nicht** mehr durch Strukturmaßnahmen optimiert. +- `Firefly` ist ebenfalls als zukünftige Löschung eingeplant und wird deshalb **nicht** mehr durch Strukturmaßnahmen optimiert. + +### Aktuelle Prioritäten statt Share-Umbau + +1. Den erfolgreichen ersten `critical_infra`-Lauf dokumentarisch abschließen und die verbleibenden Restpunkte sauber abgrenzen. +2. Pre-Backup-Dumps vor Borg automatisieren. + - Zielweg: host-seitig über Unraid User Scripts / Host-Cron + - nicht als Borg-UI-Inline-Hook in der aktuellen Architektur +3. Repo-Soll gegen Live-Ist prüfen und nur bei echtem Drift gezielt eingreifen. +4. Operative Borg-Artefakte nach `/mnt/user/backups/borg/dumps` verlagern und dort dauerhaft vom Live-App-State trennen. + +### Erläuterung zu Punkt 4 + +Diese Änderung wird ausdrücklich als **klein, risikoarm und sinnvoll** bewertet: + +- Dump-Dateien und Borg-Staging-Daten sind Backup-Artefakte, keine eigentlichen App-Daten. +- Der Zielpfad `/mnt/user/backups/borg/dumps` ist fachlich sauberer als `appdata/borg-ui/dumps`. +- Der erwartete Nutzen ist höher als bei kosmetischen Share-Umbauten, weil die Trennung zwischen Live-System und Backup-Artefakten klarer wird. + +Festgelegtes Ziel: + +- `/mnt/user/backups/borg/dumps` + +Wichtig: + +- Diese Änderung bleibt klein und risikoarm, weil nur Dump-Artefakte umziehen. +- Die Live-App-Datenpfade bleiben davon unberührt. diff --git a/ops/borg-ui/BACKUP_SCOPE.md b/ops/borg-ui/BACKUP_SCOPE.md index 02526d5..8482416 100644 --- a/ops/borg-ui/BACKUP_SCOPE.md +++ b/ops/borg-ui/BACKUP_SCOPE.md @@ -14,7 +14,7 @@ Do not back up raw live database storage directories as the primary recovery art ## Strategy -1. A pre-backup dump script runs on the host and writes fresh dumps to `/mnt/user/appdata/borg-ui/dumps/latest`. +1. A pre-backup dump script runs on the host and writes fresh dumps to `/mnt/user/backups/borg/dumps/latest`. 2. Borg backs up `/local/borg-dumps` plus the critical mounted paths below. 3. Borg retention handles history; the dump directory itself keeps only the latest artifacts. diff --git a/ops/borg-ui/docker-compose.yml b/ops/borg-ui/docker-compose.yml index fd31bec..4035cce 100644 --- a/ops/borg-ui/docker-compose.yml +++ b/ops/borg-ui/docker-compose.yml @@ -16,7 +16,7 @@ services: - /mnt/user/appdata/borg-ui/cache:/home/borg/.cache/borg - /mnt/user/appdata:/local/appdata:ro - /mnt/user/appdata/secrets:/local/secrets:ro - - /mnt/user/appdata/borg-ui/dumps:/local/borg-dumps:ro + - /mnt/user/backups/borg/dumps:/local/borg-dumps:ro - /mnt/user/documents/scans_inbox:/local/paperless/consume:ro - /mnt/user/documents/paperless:/local/paperless/media:ro - /mnt/user/documents/paperless/export:/local/paperless/export:ro diff --git a/ops/borg-ui/scripts/README.md b/ops/borg-ui/scripts/README.md index fb72dd1..7cd2bc0 100644 --- a/ops/borg-ui/scripts/README.md +++ b/ops/borg-ui/scripts/README.md @@ -10,7 +10,7 @@ These scripts are intended to run on the Unraid host before a Borg backup starts Fresh dump artifacts are written to: -- `/mnt/user/appdata/borg-ui/dumps/latest` +- `/mnt/user/backups/borg/dumps/latest` Borg UI should include `/local/borg-dumps` as a backup source. @@ -19,3 +19,21 @@ Borg UI should include `/local/borg-dumps` as a backup source. - The script is written for host execution where `docker` is available. - It does not assume Backrest. - It keeps only the latest dump set because Borg itself provides history. + +## Recommended automation path + +The recommended automation path is: + +1. Unraid User Scripts on the host +2. host-side schedule / cron +3. Borg UI backup job afterwards + +This is preferred over a Borg UI inline hook because the dump script expects: + +- host access to `docker exec` +- host paths like `/mnt/user/...` +- direct write access to the dump target directory + +Do not treat `pre-backup-dumps.sh` as a Borg UI inline script unless the architecture is deliberately changed later. + +See `USER_SCRIPTS_SETUP.md` for the intended host-side rollout. diff --git a/ops/borg-ui/scripts/USER_SCRIPTS_SETUP.md b/ops/borg-ui/scripts/USER_SCRIPTS_SETUP.md new file mode 100644 index 0000000..16d5e80 --- /dev/null +++ b/ops/borg-ui/scripts/USER_SCRIPTS_SETUP.md @@ -0,0 +1,50 @@ +# Unraid User Scripts Setup + +This document describes the intended automation path for `pre-backup-dumps.sh`. + +## Decision + +The pre-backup dump refresh should run: + +- on the Unraid host +- through the User Scripts plugin or host cron +- before the Borg UI repository job starts + +It should **not** be implemented as a Borg UI inline hook in the current design. + +## Why host-side + +`pre-backup-dumps.sh` currently assumes: + +- access to the host Docker daemon via `docker exec` +- access to host paths under `/mnt/user/...` +- the ability to write fresh dump artifacts into the shared dump directory + +That makes host execution simpler, more transparent, and lower-risk than giving Borg UI additional host-level responsibilities. + +## Recommended rollout + +1. Store the script on the host, for example at: + - `/mnt/user/appdata/borg-ui/scripts/pre-backup-dumps.sh` +2. Make it executable: + - `chmod +x /mnt/user/appdata/borg-ui/scripts/pre-backup-dumps.sh` +3. Create a User Scripts entry such as: + - `borg-pre-backup-dumps` +4. Let that entry run: + - on a fixed schedule before the expected Borg backup window + - or manually before ad hoc Borg runs +5. Keep Borg UI focused on backing up `/local/borg-dumps`, not on generating the dumps itself. + +## Operational model + +The intended sequence is: + +1. Host script refreshes `latest` dump artifacts. +2. Borg UI backs up `/local/borg-dumps` together with the rest of `critical_infra`. +3. Borg history preserves dump history, so the host only needs to keep the most recent dump set. + +## Current dump target + +- `/mnt/user/backups/borg/dumps/latest` + +This target is intentionally separate from live app state so that dump artifacts live under the backup share instead of `appdata`. diff --git a/ops/borg-ui/scripts/pre-backup-dumps.sh b/ops/borg-ui/scripts/pre-backup-dumps.sh index 15acef5..c81d2f6 100644 --- a/ops/borg-ui/scripts/pre-backup-dumps.sh +++ b/ops/borg-ui/scripts/pre-backup-dumps.sh @@ -5,7 +5,7 @@ set -eu # It refreshes the latest database dumps in a stable directory so Borg can # version the dump artifacts instead of raw live database files. -DUMP_ROOT="${DUMP_ROOT:-/mnt/user/appdata/borg-ui/dumps}" +DUMP_ROOT="${DUMP_ROOT:-/mnt/user/backups/borg/dumps}" LATEST_DIR="$DUMP_ROOT/latest" TMP_DIR="$DUMP_ROOT/.tmp" SHARED_PG_ADMIN_USER="${SHARED_PG_ADMIN_USER:-mailarchiver}"