# Dockhand Backup Kontrolliertes Backup-Tool für Docker-**Stacks**, die von [Dockhand](https://dockhand.pro/) 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 — `up` läuft in einem `finally`, 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`** (nie `tar.gz`). Ablage unter `/backup//_.tar`. - **Retention**: die letzten *N* `.tar` pro 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: 1. die **Bind-Mount-Host-Pfade**, die die Dockhand-/Docker-API meldet (nur `bind`, keine Named Volumes), 2. das **Dockhand-Stack-Verzeichnis** `/` (compose/env), 3. 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: ```bash 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 `./data` und `./backup` statt `/data` und `/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`. ```bash 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. ```bash 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.