# Backup, Restore und Monitoring im Produktivbetrieb Stand: 2026-07-15 Dieses Dokument beschreibt die für den Produktivbetrieb auf dem Webspace empfohlenen Backup-, Restore- und Monitoring-Maßnahmen. Es ergänzt `docs/betrieb-mail.md` und `docs/m8-haertung.md`. ## Backups Die App hat kein eigenes Backup-Tooling; das ist bei einer MySQL-Datenbank auf Webspace-Hosting bewusst nicht nötig – `mysqldump` reicht. Empfohlener täglicher Cron-Job (Zeitpunkt außerhalb der Hauptnutzungszeit): ```bash #!/usr/bin/env bash set -euo pipefail TIMESTAMP="$(date +%Y%m%d_%H%M%S)" BACKUP_DIR="/pfad/ausserhalb/des/webroots/backups" mkdir -p "$BACKUP_DIR" mysqldump \ --single-transaction \ --routines \ --triggers \ -h "$DB_HOST" -P "${DB_PORT:-3306}" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" \ | gzip > "$BACKUP_DIR/kaffeeliste_${TIMESTAMP}.sql.gz" # Aufbewahrung: 14 Tage taegliche Backups behalten, aeltere loeschen find "$BACKUP_DIR" -name 'kaffeeliste_*.sql.gz' -mtime +14 -delete ``` Wichtige Punkte: - `--single-transaction` sorgt für einen konsistenten Snapshot ohne Tabellen zu sperren (InnoDB, wie hier durchgängig verwendet). - Der Backup-Ordner muss **außerhalb** des über HTTP erreichbaren Webroots liegen, sonst wären Dumps öffentlich abrufbar. - Zusätzlich zu lokalen Backups auf dem Webspace mindestens eine Kopie an einen anderen Ort übertragen (z. B. verschlüsselt in Cloud-Speicher), damit ein Ausfall des Webspace-Anbieters nicht auch die Backups vernichtet. - `var/uploads`, `var/mail` und `var/sessions` enthalten keine dauerhaft relevanten Daten (Uploads werden nach Verarbeitung gelöscht, `var/mail` ist nur der Dev-Log-Transport) und müssen nicht gesichert werden. ## Restore ```bash gunzip -c kaffeeliste_20260715_030000.sql.gz | mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" ``` Danach `php scripts/migrate.php` laufen lassen, falls das Backup älter als die zuletzt eingespielten Migrationen ist (das Skript ist idempotent und wendet nur fehlende Migrationen an). **Restore-Test:** Mindestens einmal pro Quartal einen echten Restore gegen eine separate Test-Datenbank durchführen und die App dagegen starten (`scripts/run-dev-server.sh` mit den Test-DB-Zugangsdaten). Ein Backup, das nie zurückgespielt wurde, ist kein verlässliches Backup. ## Monitoring und Fehlerlogging ### PHP-Fehlerausgabe Im Dev-Modus zeigt `display_errors=1` Fehler direkt im Browser (siehe `.local/php-dev.ini`) – das ist für lokale Entwicklung richtig, aber produktiv ein Sicherheitsrisiko (Stacktraces, Dateipfade). Produktiv muss gelten: ```ini display_errors = Off log_errors = On error_log = /pfad/ausserhalb/des/webroots/logs/php-error.log ``` Die meisten Webspace-Anbieter setzen das bereits serverseitig; im Zweifel per `.htaccess` oder `ini_set()` am Anfang von `config.php` erzwingen. ### Was aktiv beobachtet werden sollte - **`php-error.log`**: Fatal Errors und Warnings. Ein plötzlicher Anstieg deutet meist auf eine kaputte Migration oder einen fehlerhaften Deploy hin. - **`audit_log`**: Ungewöhnliche Häufung sicherheitsrelevanter Aktionen (`participant.access_granted`, `tenant_settings.updated`, `year_end_bonus.distributed`, `tenant_data.exported`) außerhalb der üblichen Nutzungszeiten eines Mandanten. - **`rate_limit_attempts`**: Viele Treffer in kurzer Zeit für einen `login_ip:*`- oder `login_email:*`-Bucket zeigen einen laufenden Brute-Force-Versuch, auch wenn er durch das Rate-Limit bereits abgewehrt wird. - **`outbound_emails` mit `status = 'failed'`**: Deutet meist auf ein Problem mit dem lokalen Mailversand hin (siehe `docs/betrieb-mail.md`), zum Beispiel einen falsch konfigurierten `APP_MAIL_FROM` oder ein Zustellproblem beim Webspace-Anbieter. ### Bewusst nicht umgesetzt Ein dediziertes APM-/Monitoring-Tool (z. B. Uptime-Checks, strukturiertes Log-Shipping, Alerting) ist für den aktuellen Umfang nicht eingerichtet. Das lohnt sich erst mit echtem Produktivbetrieb und mehreren zahlenden Mandanten; bis dahin reichen die oben genannten manuellen Prüfpunkte.