Betrieb, Backup & Restore¶
Was laufen muss¶
| Komponente | Benötigt für | Prüfung |
|---|---|---|
| Web-App | Statusseite, Admin, öffentliche API, SLA-Exporte | GET /api/health liefert 200 |
| Worker | Zustellung von E-Mail, SMS, Webhook und Push, Uptime-Checks, Wartungsbeginn und automatischer Wartungsabschluss, Warnung bei fehlgeschlagenen Benachrichtigungen, Aufräumjobs | E-Mail-Events unter Information → Events wechseln von pending zu sent |
| PostgreSQL | Alles | Der Health-Check liefert 503, wenn die Datenbank nicht erreichbar ist |
Danger
Ohne Worker funktioniert die Statusseite weiter, aber es werden keine Benachrichtigungen zugestellt, Uptime-Checks laufen nicht und abgelaufene Wartungen werden erst abgeschlossen, wenn der Worker wieder läuft. Überwachen Sie den Worker-Prozess.
/api/health prüft nur den Prozess und die Datenbankverbindung. Er enthält keine Fachdaten und eignet sich für externe Probes.
Startvoraussetzungen¶
- Die Web-App startet nur mit gesetztem
SESSION_SECRET. Fehlt der Wert, bricht der Start mit einer Fehlermeldung ab. Ist er kürzer als 32 Zeichen, erscheint eine Warnung im Log. Erzeugen mitopenssl rand -hex 32. - Der Worker braucht
DATABASE_URL, denselbenSETTINGS_ENCRYPTION_KEYwie die Web-App undAPP_URLfür Links in Benachrichtigungen. - Alle Umgebungsvariablen, auch die Grenzwerte der Rate-Limits (
AUTH_RATELIMIT_*,PUBLIC_FORM_RATELIMIT_*), beschreibt Deployment, Migrationen & CI.
Backup¶
Was gesichert werden muss: die PostgreSQL-Datenbank. Sie enthält den gesamten Zustand: Incidents, SLA-Reports mit ihren bestätigten Snapshots, Einstellungen, Abonnenten, API-Tokens und die Tabellen der Job-Queues.
Was getrennt gesichert werden muss: die Geheimnisse aus der Umgebung, da sie nicht in der Datenbank liegen:
SETTINGS_ENCRYPTION_KEY. Ohne ihn können verschlüsselte Passwörter und Schlüssel in der Datenbank nicht gelesen werden.SESSION_SECRETADMIN_PASSWORD_HASH, falls noch verwendet
Dump erstellen:
pnpm db:backup [ziel] # schreibt backups/slatus-<datenbank>-<zeitstempel>.dump
Die Version von pg_dump muss mindestens der Version des Datenbankservers entsprechen. Bewahren Sie mehrere Generationen auf, legen Sie mindestens eine Kopie außerhalb des Standorts ab und sichern Sie täglich, zum Beispiel per Cron.
Verschlüsselungsschlüssel einführen oder rotieren¶
- Wurde
SETTINGS_ENCRYPTION_KEYerst nachträglich gesetzt, führen Sie einmaligpnpm db:encrypt-secretsaus. Das verschlüsselt die bisher im Klartext gespeicherten Geheimnisse. - Zum Rotieren setzen Sie den bisherigen Schlüssel als
SETTINGS_ENCRYPTION_KEY_OLDund den neuen alsSETTINGS_ENCRYPTION_KEY, führenpnpm db:rotate-secret-keyaus und entfernen danachSETTINGS_ENCRYPTION_KEY_OLD. - Gegen eine nicht lokale Datenbank laufen beide Skripte nur mit
--yes-i-am-sure. Sichern Sie vorher.
Restore¶
Das Wiederherstellen ist destruktiv. pnpm db:restore fragt vor dem Überschreiben nach (Eingabe yes) und lehnt eine DATABASE_URL, die „production“ enthält, ohne --yes-i-am-sure ab. Die Version von pg_restore muss mindestens der Version des Datenbankservers entsprechen.
- Stoppen Sie Web-App und Worker.
- Stellen Sie sicher, dass PostgreSQL läuft und eine leere Zieldatenbank existiert. Das Restore legt die Datenbank nicht an.
- Spielen Sie den Dump ein:
bash
pnpm db:restore backups/slatus-<…>.dump
- Wenden Sie ausstehende Migrationen an:
pnpm db:migrate - Starten Sie Web-App und Worker.
- Prüfen Sie den Health-Endpunkt und öffnen Sie die Statusseite.
Warning
pnpm db:seed und pnpm db:seed:history löschen Daten und sind nur für Entwicklung und Tests gedacht. Sie laufen nur gegen einen lokalen Host oder eine Datenbank, deren Name auf _dev, _e2e oder _test endet, sonst nur mit --yes-i-am-sure. Alle db:*-Skripte lesen .env.
Migrationen¶
Migrationen sind nur vorwärts gerichtet. Sie werden mit pnpm db:migrate angewendet, bevor die neue Version startet. Schlägt eine Migration fehl, finden Sie Hinweise zur Wiederherstellung in docs/context/migrations.md im Repository. Bereits angewendete Migrationen dürfen nicht verändert werden.
Routineprüfungen¶
| Intervall | Prüfung |
|---|---|
| Täglich | Fehlgeschlagene Events unter Information → Events. Erneut senden oder Ursache prüfen. Der Worker meldet fehlgeschlagene E-Mail-Events zusätzlich alle 10 Minuten als Warnung im Log. |
| Täglich | Backup-Datei vorhanden und aktuell |
| Wöchentlich | Abgelaufene API-Tokens und ungenutzte Abonnenten |
| Monatlich | Offene SLA-Reports und Ausfälle, die auf Bestätigung warten |
| Nach jeder Änderung | Öffentliche Seite und eine Test-Benachrichtigung |
Logs¶
Die Anwendung schreibt strukturierte Logs auf die Standardausgabe. In Produktion sind sie JSON, in der Entwicklung lesbarer Text. Die Log-Stufe legen Sie mit LOG_LEVEL fest (debug bis error), das Format mit LOG_FORMAT (json oder pretty). Durchsuchen Sie die Logs über die Log-Ansicht Ihrer Container-Plattform.
Warnungen, auf die Sie achten sollten:
- „notification events failed in the last window“: E-Mail-Benachrichtigungen sind fehlgeschlagen.
- „client ip is private or loopback; reverse proxy may not forward the client ip“: Der Reverse-Proxy gibt die Client-IP nicht weiter, siehe unten.
Sicherheits-Checkliste¶
- Entfernen Sie
ADMIN_PASSWORD_HASH, sobald ein Datenbank-Admin existiert. Zusätzlich können Sie den Bootstrap-Zugang mitADMIN_BOOTSTRAP_DISABLED_AFTERab einem Datum abschalten. - Setzen Sie
SESSION_SECRET(mindestens 32 Zeichen) undSETTINGS_ENCRYPTION_KEYauf zufällige Werte und bewahren Sie sie sicher auf. - Betreiben Sie die Anwendung hinter einem Reverse-Proxy mit HTTPS, der die Client-IP weitergibt, und stellen Sie
TRUSTED_PROXY_IP_HEADERpassend ein:x-real-ip, wenn der ProxyX-Real-IPsetzt, oderx-forwarded-formitTRUSTED_PROXY_COUNT, wenn er nurX-Forwarded-Forergänzt. Mit einem festen Header kann ein Client den anderen nicht fälschen. Details stehen in Deployment, Migrationen & CI. - Prüfen Sie, ob die Grenzwerte für die öffentlichen Formulare (
PUBLIC_FORM_RATELIMIT_*) zu Ihrem Besucheraufkommen passen. - Entfernen Sie
STATUS_PAGE_EMAIL_DRIVER=captureaus der Produktionsumgebung, sonst werden keine Mails versendet. - Geben Sie jeder Person die niedrigste Rolle, die ihre Aufgabe abdeckt. Siehe Rollen & Anmeldung.