cms.c2sgmbh/scripts/backup/README.md
Martin Porwoll a066539129 feat: add automated PostgreSQL backup system with S3 offsite storage
- Add backup-db.sh for daily automated backups via cron
- Add restore-db.sh for interactive database restoration
- Add setup-backup.sh for easy setup on new servers
- Support local and S3 (Hetzner Object Storage) backup locations
- 30-day retention with automatic cleanup
- Credentials stored securely in ~/.pgpass and ~/.s3cfg
- Comprehensive documentation with disaster recovery checklist

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 14:10:39 +00:00

7.2 KiB

Backup-System

Automatisches PostgreSQL-Backup mit lokalem Speicher und optionalem S3-Offsite-Backup.

Schnellstart

# Auf neuem Server einrichten
cd /home/payload/payload-cms/scripts/backup
./setup-backup.sh

Das Setup-Skript führt interaktiv durch:

  1. PostgreSQL-Authentifizierung (.pgpass)
  2. S3-Konfiguration (.s3cfg) - optional
  3. Installation des Backup-Skripts
  4. Einrichtung des Cron-Jobs
  5. Test-Backup

Manuelle Einrichtung

1. PostgreSQL-Authentifizierung

# .pgpass erstellen
echo "10.10.181.101:5432:payload_db:payload:DEIN_PASSWORT" > ~/.pgpass
chmod 600 ~/.pgpass

# Verbindung testen
psql -h 10.10.181.101 -U payload -d payload_db -c "SELECT 1"

2. S3-Konfiguration (optional)

# s3cmd installieren
sudo apt install s3cmd

# .s3cfg erstellen
cat > ~/.s3cfg << 'EOF'
[default]
access_key = DEIN_ACCESS_KEY
secret_key = DEIN_SECRET_KEY
host_base = fsn1.your-objectstorage.com
host_bucket = %(bucket)s.fsn1.your-objectstorage.com
use_https = True
signature_v2 = False
EOF
chmod 600 ~/.s3cfg

# Verbindung testen
s3cmd ls

3. Backup-Skript installieren

# Verzeichnis erstellen
mkdir -p /home/payload/backups/postgres

# Skript kopieren
cp scripts/backup/backup-db.sh /home/payload/backups/postgres/
chmod +x /home/payload/backups/postgres/backup-db.sh

# Test
/home/payload/backups/postgres/backup-db.sh --verbose

4. Cron-Job einrichten

# Crontab bearbeiten
crontab -e

# Zeile hinzufügen (täglich um 03:00 Uhr)
0 3 * * * /home/payload/backups/postgres/backup-db.sh >> /home/payload/logs/backup-cron.log 2>&1

Backup-Skript Optionen

# Normales Backup (für Cron)
./backup-db.sh

# Mit detaillierter Ausgabe
./backup-db.sh --verbose

Umgebungsvariablen

Variable Default Beschreibung
PGHOST 10.10.181.101 PostgreSQL Host
PGPORT 5432 PostgreSQL Port
PGDATABASE payload_db Datenbank-Name
PGUSER payload Datenbank-User
S3_BACKUP_ENABLED true S3-Upload aktivieren
S3_BUCKET c2s S3-Bucket-Name
S3_PATH backups/postgres Pfad im Bucket

Backup-Speicherorte

Ort Pfad Retention
Lokal /home/payload/backups/postgres/ 30 Tage
S3 s3://c2s/backups/postgres/ 30 Tage

Log-Dateien

Datei Beschreibung
/home/payload/backups/postgres/backup.log Detailliertes Backup-Log
/home/payload/logs/backup-cron.log Cron-Ausgabe

Das Backup-Log wird automatisch rotiert (max. 10MB, behält letzte 1000 Zeilen).

Restore

Restore-Skript (empfohlen)

Das interaktive Restore-Skript führt sicher durch den Wiederherstellungsprozess:

# Interaktive Auswahl aus lokalen Backups
./restore-db.sh

# Interaktive Auswahl aus S3-Backups
./restore-db.sh --from-s3

# Direktes Restore aus lokaler Datei
./restore-db.sh /home/payload/backups/postgres/payload_db_2025-12-11_03-00-00.sql.gz

# Direktes Restore aus S3
./restore-db.sh --from-s3 payload_db_2025-12-11_03-00-00.sql.gz

# Backups auflisten
./restore-db.sh --list      # Lokale Backups
./restore-db.sh --list-s3   # S3-Backups

Das Restore-Skript führt automatisch durch:

  1. Prüfung der Datenbankverbindung
  2. Auflistung verfügbarer Backups
  3. Download von S3 (falls gewählt)
  4. Verifizierung der Backup-Integrität
  5. Stoppen von Payload CMS und Queue-Worker
  6. Durchführung des Restores
  7. Verifizierung der wiederhergestellten Daten
  8. Neustart der Anwendung

Manueller Restore-Prozess

Falls das Skript nicht verfügbar ist:

Schritt 1: Anwendung stoppen

pm2 stop payload
pm2 stop queue-worker

Schritt 2: Backup auswählen

# Lokale Backups anzeigen
ls -lah /home/payload/backups/postgres/*.sql.gz

# S3-Backups anzeigen
s3cmd ls s3://c2s/backups/postgres/

Schritt 3: Backup herunterladen (nur bei S3)

s3cmd get s3://c2s/backups/postgres/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz /tmp/

Schritt 4: Backup verifizieren

# Integrität prüfen
gzip -t /tmp/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz && echo "OK" || echo "BESCHÄDIGT"

# Inhalt inspizieren (erste 50 Zeilen)
gunzip -c /tmp/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz | head -50

Schritt 5: Restore durchführen

# Aus lokalem Backup
gunzip -c /home/payload/backups/postgres/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz | \
  psql -h 10.10.181.101 -U payload -d payload_db

# Aus heruntergeladenem S3-Backup
gunzip -c /tmp/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz | \
  psql -h 10.10.181.101 -U payload -d payload_db

Schritt 6: Restore verifizieren

# Tabellen zählen
psql -h 10.10.181.101 -U payload -d payload_db -c \
  "SELECT COUNT(*) as tables FROM information_schema.tables WHERE table_schema = 'public';"

# Zeilen in wichtigen Tabellen prüfen
psql -h 10.10.181.101 -U payload -d payload_db -c \
  "SELECT 'users' as table, COUNT(*) as rows FROM users
   UNION ALL SELECT 'tenants', COUNT(*) FROM tenants
   UNION ALL SELECT 'posts', COUNT(*) FROM posts
   UNION ALL SELECT 'pages', COUNT(*) FROM pages;"

Schritt 7: Anwendung starten

pm2 start payload
pm2 start queue-worker
pm2 status

Schritt 8: Funktionalität testen

  1. Admin-Panel öffnen: https://pl.c2sgmbh.de/admin
  2. Login testen
  3. Stichprobenartig Inhalte prüfen

Disaster Recovery Checkliste

Bei vollständigem Systemausfall:

□ 1. Neuen Server bereitstellen
□ 2. Repository klonen: git clone https://github.com/c2s-admin/cms.c2sgmbh.git
□ 3. Dependencies installieren: pnpm install
□ 4. .env konfigurieren (aus Dokumentation oder Backup)
□ 5. Backup-System einrichten: ./scripts/backup/setup-backup.sh
□ 6. Neuestes Backup von S3 holen: s3cmd ls s3://c2s/backups/postgres/
□ 7. Restore durchführen: ./scripts/backup/restore-db.sh --from-s3
□ 8. Build erstellen: pnpm build
□ 9. Anwendung starten: pm2 start ecosystem.config.cjs
□ 10. DNS/Reverse Proxy konfigurieren
□ 11. SSL-Zertifikate einrichten (Caddy automatisch)
□ 12. Funktionalität testen

Point-in-Time Recovery

Für Recovery zu einem bestimmten Zeitpunkt:

  1. Backup VOR dem gewünschten Zeitpunkt identifizieren
  2. Restore durchführen
  3. Manuelle Nacharbeit für Daten zwischen Backup und Zielzeitpunkt

Hinweis: Für echtes Point-in-Time Recovery wäre PostgreSQL WAL-Archivierung erforderlich (nicht implementiert).

Sicherheit

  • Keine Credentials im Skript: Passwörter werden aus ~/.pgpass und ~/.s3cfg gelesen
  • Berechtigungen: Beide Dateien müssen chmod 600 haben
  • Credential-Dateien nicht committen: .pgpass und .s3cfg sind in .gitignore

Troubleshooting

Backup fehlgeschlagen

# Log prüfen
tail -50 /home/payload/backups/postgres/backup.log

# Datenbankverbindung testen
psql -h 10.10.181.101 -U payload -d payload_db -c "SELECT 1"

# .pgpass Berechtigungen prüfen
ls -la ~/.pgpass  # Muss 600 sein

S3-Upload fehlgeschlagen

# S3-Verbindung testen
s3cmd ls

# .s3cfg Berechtigungen prüfen
ls -la ~/.s3cfg  # Muss 600 sein

# S3 manuell testen
s3cmd put testfile.txt s3://c2s/test/

Cron läuft nicht

# Crontab prüfen
crontab -l

# Cron-Log prüfen
tail -50 /home/payload/logs/backup-cron.log

# Cron-Service Status
systemctl status cron