Reviewed-on: #1
Dockhand Backup
Kontrolliertes Backup-Tool für Docker-Stacks, die von Dockhand
verwaltet werden. Es fährt jeden Stack geordnet über die Dockhand-API herunter (down),
sichert die Daten als unkomprimiertes .tar und fährt ihn sofort wieder hoch (up) —
im Gegensatz zum Unraid-eigenen Backup, das Container willkürlich stoppt und
Abhängigkeiten zerstört.
Eigenschaften
- Cold-Backup pro Stack: immer nur EIN Stack ist unten (
down → tar → up). Ein Stack wird nie unten gelassen —upläuft in einemfinally, auch wenn das Tarren scheitert. - Reihenfolge & Ausschluss pro Stack (per Drag&Drop im Dashboard).
- Auto-Discovery: neue Stacks werden vor jedem geplanten Lauf automatisch erkannt und aufgenommen.
- Format immer
tar(nietar.gz). Ablage unter/backup/<stack>/<stack>_<ts>.tar. - Retention: die letzten N
.tarpro Stack behalten. - Beliebige Pfade zusätzlich sichern (z.B. das Dockhand-Stack-Verzeichnis mit compose/env), global oder pro Stack.
- JSON als „DB" (
/data/config.json) — keine echte Datenbank. - Flask + Tailwind UI, geschützt per Authentik OIDC (optional).
- Zeitplan per Cron (APScheduler).
Wie es sichert
Für jeden Stack werden getarrt:
- die Bind-Mount-Host-Pfade, die die Dockhand-/Docker-API meldet
(nur
bind, keine Named Volumes), - das Dockhand-Stack-Verzeichnis
<dockhand_stacks_base>/<stack>(compose/env), - stack-eigene Extra-Pfade.
Diese Pfade müssen im Backup-Container unter demselben absoluten Pfad gemountet sein, wie Dockhand sie zurückgibt (siehe
docker-compose.example.yml, z.B./mnt/user:/mnt/user:ro).
Archiv-Einträge werden ohne führendes / gespeichert. Wiederherstellen an den
Originalort:
tar xf media_20260713-030000.tar -C /
Dev-Modus (lokal testen, ohne Docker)
Läuft die App außerhalb von Docker (kein /.dockerenv), schaltet sie automatisch in den
Dev-Modus:
- lokale Ordner
./dataund./backupstatt/dataund/backup, - ohne konfigurierte Dockhand-Zugangsdaten ein Mock-Dockhand mit Beispiel-Stacks,
- Simulation: es werden weder echte Stacks gestoppt/gestartet noch echte Host-Pfade
getarrt — jeder Lauf schreibt nur ein winziges Platzhalter-
.tar. So testest du die Oberfläche und den Ablauf gefahrlos.
Erzwingen/abschalten via Env-Var DEV_MODE=true|false.
python -m venv .venv && .venv/Scripts/activate # Windows
pip install -r requirements.txt
python wsgi.py # http://localhost:8080 (Tailwind via Play-CDN)
Willst du im Dev-Modus gegen dein echtes Dockhand listen (aber weiter simuliert
sichern), setze DOCKHAND_URL/DOCKHAND_USER/DOCKHAND_PASS.
Deployment (Docker / Unraid)
Die Prod-Compose (docker-compose.yml) zieht das fertige Image aus der Gitea-Registry und
liest alle Werte aus einer .env daneben (nichts Sensibles im Repo). Kein Port-Mapping —
der Container hängt im externen Netzwerk nginx hinter dem Reverse-Proxy.
cp .env.example .env # Secrets/Pfade eintragen (DOCKHAND_*, FLASK_SECRET_KEY, BACKUP_DIR, ...)
docker compose up -d
Voraussetzung: das externe Docker-Netzwerk nginx existiert und das Image wurde per CI
gebaut/gepusht (siehe .gitea/workflows/). Das Image kompiliert Tailwind mit der
Standalone-CLI in app/static/app.css — zur Laufzeit wird kein CDN benötigt.
Projektstruktur
app/ # Python-Package
settings.py # Env-basierte Settings (+ Dev-Modus)
store.py # JSON-"DB" (atomar, gelockt)
dockhand.py # Dockhand-API-Client (+ Mock)
backup.py # Backup-Engine
scheduler.py # APScheduler (Cron)
auth.py # Authentik-OIDC-Login
routes.py # Flask-Routes
templates/ # Jinja + Tailwind
static/ # src.css, app.css (build), vendor/sortable.min.js
docker/Dockerfile # Multi-stage build (NICHT im Image)
docker-compose.yml # Prod-Compose (Registry-Image, .env-gesteuert)
.gitea/workflows/ # CI: build+push Image, Release-Automation
wsgi.py # Entrypoint
Hinweis
Gitea-Workflows werden vom Betreiber separat ergänzt.