electric-horses-infra/docs/runbooks/forgejo-backup-restore.md

139 lines
4.1 KiB
Markdown
Raw Normal View History

# 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-<YYYYMMDD-HHMMSS>.sql.gz` — pg_dump der Postgres DB
- `forgejo-data-<YYYYMMDD-HHMMSS>.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-<TIMESTAMP>.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-<TIMESTAMP>.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-<TIMESTAMP>.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-<TIMESTAMP>.tar.gz | head -30
# Einzelne Datei extrahieren
mkdir -p /tmp/forgejo-restore
tar -xzf /opt/backups/forgejo/forgejo-data-<TIMESTAMP>.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)