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

303 lines
7.2 KiB
Markdown

# Backup-System
Automatisches PostgreSQL-Backup mit lokalem Speicher und optionalem S3-Offsite-Backup.
## Schnellstart
```bash
# 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
```bash
# .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)
```bash
# 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
```bash
# 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
```bash
# 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
```bash
# 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:
```bash
# 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
```bash
pm2 stop payload
pm2 stop queue-worker
```
#### Schritt 2: Backup auswählen
```bash
# 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)
```bash
s3cmd get s3://c2s/backups/postgres/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz /tmp/
```
#### Schritt 4: Backup verifizieren
```bash
# 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
```bash
# 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
```bash
# 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
```bash
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
```bash
# 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
```bash
# 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
```bash
# Crontab prüfen
crontab -l
# Cron-Log prüfen
tail -50 /home/payload/logs/backup-cron.log
# Cron-Service Status
systemctl status cron
```