# Deployment Guide - Payload CMS Multi-Tenant *Letzte Aktualisierung: 27. Dezember 2025* > **Wichtig:** Für die vollständige Deployment-Strategie siehe [DEPLOYMENT_STRATEGY.md](./DEPLOYMENT_STRATEGY.md) ## Übersicht Dieses Dokument beschreibt den Deployment-Prozess für das Payload CMS Multi-Tenant-System. ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ DEVELOPMENT │ │ STAGING │ │ PRODUCTION │ │ │ │ │ │ │ │ sv-frontend │────▶│ sv-payload │────▶│ Hetzner 3 │ │ Local Dev │ │ pl.porwoll.tech │ │ cms.c2sgmbh.de │ │ │ │ │ │ │ │ develop branch │ │ develop branch │ │ main branch │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` --- ## Umgebungen | Umgebung | Server | URL | Branch | Zweck | |----------|--------|-----|--------|-------| | **Development** | sv-payload (LXC 700) | https://pl.porwoll.tech | `develop` | Entwicklung & Testing | | **Production** | Hetzner 3 | https://cms.c2sgmbh.de | `main` | Live-System | --- ## Staging Deployment (Development → pl.porwoll.tech) ### Automatisch via GitHub Actions Bei jedem Push auf `develop` wird automatisch deployed: ```yaml # .github/workflows/deploy-staging.yml on: push: branches: [develop] ``` **Ablauf:** 1. Pre-deployment Checks (Lint, Tests) 2. SSH-Verbindung zu sv-payload 3. `git pull origin develop` 4. `pnpm install` 5. `pnpm payload migrate` 6. `pnpm build` 7. `pm2 restart payload` 8. Health Check ### Manuell auf sv-payload ```bash # SSH zum Server ssh payload@10.10.181.100 # Ins Projektverzeichnis cd /home/payload/payload-cms # Änderungen holen git pull origin develop # Dependencies aktualisieren pnpm install # Migrationen ausführen (falls vorhanden) pnpm payload migrate # Build erstellen pnpm build # PM2 neustarten pm2 restart payload # Logs prüfen pm2 logs payload --lines 20 ``` ### Mit Deploy-Script ```bash # Auf sv-payload ./scripts/deploy-staging.sh # Optionen: ./scripts/deploy-staging.sh --skip-build # Nur Code-Update ./scripts/deploy-staging.sh --skip-migrations # Ohne Migrationen ``` --- ## Production Deployment (main → cms.c2sgmbh.de) ### Option A: Via GitHub Actions (Empfohlen) 1. **develop in main mergen und pushen** ```bash git checkout main git pull origin main git merge develop git push origin main ``` 2. **GitHub Actions Workflow starten** - Gehe zu: Actions → "Deploy to Production" → "Run workflow" - Oder via CLI: ```bash gh workflow run deploy-production.yml ``` 3. **Der Workflow führt automatisch aus:** - Pre-flight Checks - Tests (optional) - Datenbank-Backup - Deployment - Health Check - Bei Fehler: Automatischer Rollback ### Option B: Via Deploy-Script auf Server ```bash # SSH zum Production-Server ssh payload@162.55.85.18 # Deploy-Script ausführen (mit Backup, Health Check, Rollback-Fähigkeit) cd ~/payload-cms ./scripts/deploy-production.sh # Optionen: ./scripts/deploy-production.sh -y # Ohne Bestätigung ./scripts/deploy-production.sh --skip-backup # Ohne Backup (nicht empfohlen) ./scripts/deploy-production.sh --skip-build # Nur Service-Neustart ./scripts/deploy-production.sh --rollback # Rollback zur vorherigen Version ./scripts/deploy-production.sh --dry-run # Zeigt was passieren würde ``` ### Rollback bei Problemen ```bash # Automatischer Rollback zur vorherigen Version ./scripts/deploy-production.sh --rollback # Oder manuell zu spezifischem Commit git log --oneline -10 git reset --hard pnpm install --frozen-lockfile pnpm build pm2 restart payload ``` --- ## Rollback ### Auf vorherigen Commit zurücksetzen ```bash # Letzten funktionierenden Commit finden git log --oneline -10 # Zurücksetzen (VORSICHT: Ändert History nicht) git checkout pnpm install pnpm build pm2 restart payload # Oder: Hard Reset (VORSICHT: Ändert History) git reset --hard git push --force origin main # Nur im Notfall! ``` ### Datenbank-Rollback ```bash # Backup wiederherstellen (nur bei Datenverlust) gunzip -c ~/backups/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz | \ psql -h localhost -U payload -d payload_db ``` --- ## Migrationen ### Migration erstellen ```bash # Auf Development-Server pnpm payload migrate:create # Generiert: src/migrations/YYYYMMDD_HHMMSS_.ts ``` ### Migration ausführen ```bash # Normale Ausführung pnpm payload migrate # Bei PgBouncer-Problemen: Direkte Verbindung ./scripts/db-direct.sh migrate ``` ### Migration-Status prüfen ```bash pnpm payload migrate:status ``` --- ## Build-Konfiguration ### Memory-Limits Der Server hat 8GB RAM. Build-Einstellungen: ```json // package.json { "scripts": { "build": "cross-env NODE_OPTIONS='--no-deprecation --max-old-space-size=2048' next build" } } ``` ### Bei Memory-Problemen ```bash # PM2 stoppen um Speicher freizugeben pm2 stop payload # Build mit reduziertem Memory NODE_OPTIONS="--no-deprecation --max-old-space-size=1024" pnpm build # PM2 wieder starten pm2 start payload ``` --- ## PM2 Konfiguration ### ecosystem.config.cjs ```javascript module.exports = { apps: [ { name: 'payload', script: 'node_modules/.bin/next', args: 'start', cwd: '/home/payload/payload-cms', instances: 1, max_memory_restart: '2G', env: { NODE_ENV: 'production', PORT: 3000 } }, { name: 'queue-worker', script: './scripts/run-queue-worker.ts', interpreter: 'node', interpreter_args: '--import tsx', cwd: '/home/payload/payload-cms', instances: 1, max_memory_restart: '500M' } ] } ``` ### PM2 Befehle ```bash pm2 status # Status aller Prozesse pm2 logs payload # Logs anzeigen pm2 logs queue-worker # Queue-Worker Logs pm2 restart payload # Neustart pm2 restart all # Alle neustarten pm2 save # Autostart-Konfiguration speichern pm2 startup # Systemd-Integration ``` --- ## Health Checks ### Nach Deployment prüfen ```bash # 1. PM2 Status pm2 status # 2. Logs auf Fehler prüfen pm2 logs payload --lines 50 # 3. API erreichbar? curl -I https://cms.c2sgmbh.de/api/users # 4. Admin Panel erreichbar? curl -I https://cms.c2sgmbh.de/admin # 5. Redis verbunden? redis-cli ping ``` ### Automatischer Health Check ```bash #!/bin/bash # health-check.sh API_URL="https://cms.c2sgmbh.de/api" ADMIN_URL="https://cms.c2sgmbh.de/admin" # API Check if curl -sf "$API_URL/users" > /dev/null; then echo "✅ API OK" else echo "❌ API FAILED" exit 1 fi # Admin Check if curl -sf "$ADMIN_URL" > /dev/null; then echo "✅ Admin OK" else echo "❌ Admin FAILED" exit 1 fi echo "✅ All checks passed" ``` --- ## Umgebungsvariablen ### Production (.env) ```env # Datenbank DATABASE_URI=postgresql://payload:***@localhost:5432/payload_db PAYLOAD_SECRET=*** # URLs PAYLOAD_PUBLIC_SERVER_URL=https://cms.c2sgmbh.de NEXT_PUBLIC_SERVER_URL=https://cms.c2sgmbh.de # Environment NODE_ENV=production PORT=3001 # Redis REDIS_URL=redis://localhost:6379 # Security CSRF_SECRET=*** TRUST_PROXY=true ``` ### Staging (.env) ```env # Datenbank (via PgBouncer) DATABASE_URI=postgresql://payload:***@127.0.0.1:6432/payload_db PAYLOAD_SECRET=*** # URLs PAYLOAD_PUBLIC_SERVER_URL=https://pl.porwoll.tech NEXT_PUBLIC_SERVER_URL=https://pl.porwoll.tech # Environment NODE_ENV=production PORT=3000 # Redis REDIS_URL=redis://localhost:6379 # Security CSRF_SECRET=*** TRUST_PROXY=true ``` --- ## CI/CD Pipeline ### GitHub Actions Workflows | Workflow | Trigger | Aktion | |----------|---------|--------| | `ci.yml` | Push/PR auf main, develop | Lint, Test, Build, E2E | | `security.yml` | Push/PR, Schedule | Security Scanning | | `deploy-staging.yml` | Push auf develop | Auto-Deploy zu Staging | | `deploy-production.yml` | Manuell (workflow_dispatch) | Production Deployment | ### Secrets (GitHub) | Secret | Beschreibung | |--------|--------------| | `STAGING_SSH_KEY` | SSH Private Key für sv-payload | | `PRODUCTION_SSH_KEY` | SSH Private Key für Hetzner 3 | ### Manuelles Deployment triggern ```bash # Via GitHub CLI gh workflow run deploy-staging.yml # Mit skip_tests Option gh workflow run deploy-staging.yml -f skip_tests=true ``` --- ## Backup vor Deployment ### Automatisches Backup Backups laufen täglich um 03:00 Uhr. Vor großen Deployments manuell: ```bash # Auf Production ~/backup.sh # Auf Staging /home/payload/backups/postgres/backup-db.sh --verbose ``` ### Backup-Speicherorte | Server | Lokal | Offsite | |--------|-------|---------| | Production | ~/backups/ | - | | Staging | /home/payload/backups/postgres/ | s3://c2s/backups/postgres/ | --- ## Troubleshooting ### Build schlägt fehl ```bash # Cache löschen rm -rf .next pnpm build # Mit mehr Speicher NODE_OPTIONS="--max-old-space-size=4096" pnpm build ``` ### PM2 startet nicht ```bash # Logs prüfen pm2 logs payload --lines 100 # Prozess komplett entfernen und neu starten pm2 delete payload pm2 start ecosystem.config.cjs ``` ### Datenbank-Verbindung fehlgeschlagen ```bash # PgBouncer Status (Staging) sudo systemctl status pgbouncer # PostgreSQL Status (Production) sudo systemctl status postgresql # Verbindung testen psql -h localhost -U payload -d payload_db -c "SELECT 1" ``` ### Migration fehlgeschlagen ```bash # Status prüfen pnpm payload migrate:status # Bei PgBouncer-Problemen ./scripts/db-direct.sh migrate # Einzelne Migration manuell pnpm payload migrate --name 20251216_073000_add_video_collections ``` --- ## Checkliste ### Vor dem Deployment - [ ] Alle Tests grün (`pnpm test`) - [ ] Build erfolgreich (`pnpm build`) - [ ] Migrationen getestet auf Staging - [ ] Backup erstellt (bei Datenbank-Änderungen) - [ ] CLAUDE.md/Docs aktualisiert (bei neuen Features) ### Nach dem Deployment - [ ] `pm2 status` - Prozesse online - [ ] Admin Panel erreichbar - [ ] API funktioniert - [ ] Logs auf Fehler geprüft - [ ] Neue Features manuell getestet --- ## Kontakte | Rolle | Kontakt | |-------|---------| | Server Admin | Martin Porwoll | | Repository | https://github.com/complexcaresolutions/cms.c2sgmbh | --- *Dokumentation: Complex Care Solutions GmbH | 29.12.2025*