# Runbook — Forgejo Backup und Restore ## Backup-Architektur - **Script:** `/opt/ai-apps/forgejo/backup.sh` - **Cron:** `0 3 * * *` (täglich 03:00 UTC auf ai-apps) - **Ziel:** `/opt/backups/forgejo/` - **Format:** - `forgejo-db-.sql.gz` — pg_dump der Postgres DB - `forgejo-data-.tar.gz` — tar des Forgejo `/data` Volumes - **Retention:** 14 Tage (ältere Dateien werden via `find -mtime +14 -delete` entfernt) ## Manueller Backup-Run ```bash ssh ai-apps bash /opt/ai-apps/forgejo/backup.sh ls -lh /opt/backups/forgejo/ ``` Erwartete Ausgabe: ``` [2026-04-11T19:39:11+00:00] backup start db dump: 26K data tar: 12K [2026-04-11T19:39:12+00:00] backup complete ``` ## Restore-Szenarien ### Szenario A: Komplett-Restore aus Backup (Disaster Recovery) Voraussetzung: Backup-Files sind vorhanden (entweder in `/opt/backups/forgejo/` oder aus Offsite-Kopie). ```bash # 1. Stack stoppen cd /opt/ai-apps/forgejo docker compose down # 2. Volumes löschen (ACHTUNG: unwiderruflich!) docker volume rm forgejo_forgejo-data forgejo_forgejo-db-data # 3. Stack wieder starten — leere Volumes werden neu angelegt docker compose up -d forgejo-db # 4. Warten bis Postgres healthy sleep 20 docker ps --filter name=forgejo-db --format '{{.Status}}' # Up (healthy) # 5. DB restoren gunzip -c /opt/backups/forgejo/forgejo-db-.sql.gz | \ docker exec -i forgejo-db psql -U forgejo -d forgejo # 6. Data volume restoren docker run --rm \ -v forgejo_forgejo-data:/data \ -v /opt/backups/forgejo:/backup:ro \ alpine \ sh -c "cd /data && tar -xzf /backup/forgejo-data-.tar.gz" # 7. Forgejo starten docker compose up -d forgejo # 8. Verifikation sleep 30 curl -s https://code.sdda.eu/api/healthz curl -s https://code.sdda.eu/api/v1/version docker exec -u git forgejo sh -c 'cd / && forgejo admin user list' ``` ### Szenario B: Nur DB zurückspielen (z.B. nach Korruption durch Update) ```bash cd /opt/ai-apps/forgejo docker compose stop forgejo # nur Forgejo, nicht DB # DB mit -c wipen und neu importieren docker exec forgejo-db psql -U forgejo -d postgres \ -c "DROP DATABASE forgejo;" docker exec forgejo-db psql -U forgejo -d postgres \ -c "CREATE DATABASE forgejo OWNER forgejo;" gunzip -c /opt/backups/forgejo/forgejo-db-.sql.gz | \ docker exec -i forgejo-db psql -U forgejo -d forgejo docker compose start forgejo ``` ### Szenario C: Einzelne Datei / Config aus Data-Volume wiederherstellen ```bash # Tar-Inhalt inspizieren tar -tzf /opt/backups/forgejo/forgejo-data-.tar.gz | head -30 # Einzelne Datei extrahieren mkdir -p /tmp/forgejo-restore tar -xzf /opt/backups/forgejo/forgejo-data-.tar.gz \ -C /tmp/forgejo-restore gitea/conf/app.ini # Ins laufende Volume kopieren docker cp /tmp/forgejo-restore/gitea/conf/app.ini forgejo:/data/gitea/conf/app.ini docker restart forgejo ``` ## Disaster-Recovery: Kompletter Neuaufbau auf neuem Server 1. Neuen Host aufsetzen (Docker + Compose) 2. `/opt/ai-apps/forgejo/` Stack-Verzeichnis kopieren (inkl. `.env`, docker-compose.yml, backup.sh) 3. Backup-Files aus Offsite-Quelle holen (Nextcloud / Hetzner Snapshot) 4. Szenario A durchführen 5. DNS ggf. auf neue IP anpassen ## Verification nach Restore ```bash # Health curl -s https://code.sdda.eu/api/healthz # Auth-Sources docker exec -u git forgejo sh -c 'cd / && forgejo admin auth list' # Erwartet: 1 authentik OAuth2 true # User docker exec -u git forgejo sh -c 'cd / && forgejo admin user list' # Erwartet: admin-local + bw + alle anderen # Repo-Zähler docker exec forgejo-db psql -U forgejo -d forgejo \ -c "SELECT count(*) FROM repository;" ``` ## Offsite-Backup-Strategie (zukünftig, M7.5) - **Tier 2:** rclone → Nextcloud, zweiter Cron 03:30 - **Tier 3:** Hetzner Cloud Snapshot, manuell wöchentlich Beides noch nicht eingerichtet — solange lokale 14-Tage-Retention + Hetzner-VM-Stabilität unser Sicherheitsnetz. ## Was NIE machen - Backup-Files niemals in Git einchecken (können sensible Repo-Daten enthalten) - Restore auf laufender Prod ohne vorheriges Backup (einfach `docker compose down` macht keine DB-Kopie!) - `docker volume prune` wenn Forgejo noch läuft (wird Daten verlieren)