# Betrieb: Backup und Wiederherstellung ## Neu: Passwort und Ziele in der Oberfläche Unter **Einstellungen → Backup** (nur Superadministratoren dürfen ändern): - **Backup-Passwort**: selbst wählbar, mindestens 11 Zeichen (länger als 10), mit Wiederholung und Bestätigung durch das Anmeldepasswort. Neue Sicherungen werden damit per **gpg (AES-256, Integritätsschutz)** verschlüsselt (`*.tar.gz.gpg`). Das Passwort liegt mit dem Master-Schlüssel verschlüsselt in der Datenbank, wird nie angezeigt oder protokolliert und lässt sich **nicht wiederherstellen**. Nach einer Änderung bleiben ältere Sicherungen mit dem alten Passwort verschlüsselt. Ohne Passwort und ohne age-Schlüssel wird nichts gesichert (nie unverschlüsselt). - **Externe Ziele**: SFTP (Passwort oder Schlüssel; Server-Schlüssel wird beim ersten Test gemerkt und angezeigt, ein anderer Server wird danach abgelehnt), FTP/FTPS, Google Drive (Token aus `rclone authorize`), Ordner/Netzlaufwerk (eingehängt, z. B. `/mnt/nas/...`). Zugangsdaten werden verschlüsselt gespeichert und nie wieder angezeigt. „Testen“ legt den Ordner an, schreibt und löscht eine Testdatei. Ziele lassen sich deaktivieren oder entfernen (bereits abgelegte Sicherungen bleiben). - Alte Sicherungen mit `.age` bleiben mit der Schlüsseldatei lesbar; der Wiederherstellungstest erkennt die Art an der Dateiendung. **Entschlüsseln im Notfall (nur mit Standardwerkzeug):** ```bash gpg -d -o archive.tar.gz kundencenter-DATUM-....tar.gz.gpg # fragt nach dem Backup-Passwort ``` ## Überblick - **Was wird gesichert:** Datenbank `kundencenter` (Dump) + Konfiguration mit dem Master-Schlüssel (`app.env`, `db.env`, `discord.env`). Ohne `KC_SECRET_KEY` wären 2FA- und Verbindungs-Geheimnisse in einem Backup unlesbar, deshalb ist er enthalten. **Nicht** enthalten: der private Backup-Schlüssel, Plane-Zugang, das Lizenzsystem (eigenes System, eigenes Backup). - **Verschlüsselung:** `age` (öffentlicher Schlüssel `BACKUP_AGE_RECIPIENT`). Ziele (NAS, FTP, Google Drive) sehen nur verschlüsselte Dateien. - **Zeitplan:** täglich ca. 02:30 (`kc-backup.timer`), Wiederherstellungstest sonntags ca. 04:30 (`kc-restore-test.timer`). Verpasste Läufe werden nachgeholt (`Persistent`). - **Aufbewahrung** (lokal und auf jedem Ziel): 14 tägliche, 8 wöchentliche, 12 monatliche Sicherungen; immer mindestens 3 bleiben erhalten. Fremde Dateien werden nie gelöscht. - **Ablage lokal:** `/var/backups/kundencenter/` (Rechte 700). Das ersetzt kein externes Ziel: bei Verlust des Servers ist es weg. - **Kontrolle:** Übersicht (Personal) zeigt letzten Lauf, Ziele und Wiederherstellungstest. Bei fehlgeschlagenem Lauf oder mehr als 26 h ohne Erfolg geht eine Meldung an Discord (ohne Nutzdaten, sobald der Bot eingerichtet ist). Status: `/var/lib/kundencenter/backup-status.json`, Logs: `journalctl -u kc-backup`. - **Wiederherstellungstest** (automatisch): entschlüsselt die neueste Sicherung, spielt sie in die Wegwerf-Datenbank `kundencenter_restoretest` ein und prüft Prüfsummen, Zeilenzahlen aller Kerntabellen, Migrationen, Audit-Hash-Kette und ob gesicherte Geheimnisse mit dem gesicherten Schlüssel lesbar sind. Produktivdaten bleiben unberührt. ## WICHTIG: privaten Schlüssel extern sichern Der private Schlüssel liegt in `/etc/kundencenter/backup-age-key.txt` (Rechte 600). **Ohne ihn sind alle Backups wertlos.** Bitte einmalig eine Kopie an einem sicheren Ort ablegen (Passwortmanager, Tresor), **nicht** im selben Cloud-Ziel wie die Backups: ```bash cat /etc/kundencenter/backup-age-key.txt # Inhalt (zwei Kommentarzeilen + Schlüsselzeile AGE-SECRET-KEY-...) sicher kopieren ``` Der Schlüssel liegt auf dem Server, damit der automatische Wiederherstellungstest laufen kann. Wer den Server kontrolliert, hat ohnehin Zugriff auf die Datenbank. ## Backup-Ziele per Kommandozeile (Alternative zur Oberfläche) Zugangsdaten der Ziele stehen in `/var/lib/kundencenter/rclone.conf` (nur root). Alle Befehle mit `--config /var/lib/kundencenter/rclone.conf`. **SFTP (empfohlen: Schlüssel statt Passwort)** ```bash ssh-keygen -t ed25519 -N "" -f /var/lib/kundencenter/backup_ed25519 cat /var/lib/kundencenter/backup_ed25519.pub # auf dem Ziel in ~/.ssh/authorized_keys eintragen ssh-keyscan -H ZIELHOST > /var/lib/kundencenter/known_hosts rclone config create nas sftp host=ZIELHOST user=BENUTZER key_file=/var/lib/kundencenter/backup_ed25519 known_hosts_file=/var/lib/kundencenter/known_hosts --config /var/lib/kundencenter/rclone.conf rclone mkdir nas:kundencenter --config /var/lib/kundencenter/rclone.conf && rclone lsd nas: --config /var/lib/kundencenter/rclone.conf ``` **FTP/FTPS** ```bash rclone config create ftpziel ftp host=ZIELHOST user=BENUTZER pass="$(rclone obscure 'PASSWORT')" explicit_tls=true --config /var/lib/kundencenter/rclone.conf ``` (Nur unverschlüsseltes FTP möglich? Dann `explicit_tls=false`; die Backups sind trotzdem verschlüsselt, Zugangsdaten gehen aber im Klartext über das Netz.) **Google Drive** (OAuth, einmalig auf einem Rechner mit Browser) ```bash # auf dem Rechner mit Browser (rclone dort installieren): rclone authorize "drive" "eyJzY29wZSI6ImRyaXZlLmZpbGUifQ" # Scope drive.file: nur von rclone angelegte Dateien # ausgegebenen Token kopieren, dann auf dem Server: rclone config create gdrive drive scope=drive.file token='{"access_token":...}' --config /var/lib/kundencenter/rclone.conf ``` Empfehlung: eigene OAuth-Client-ID (Google Cloud) verwenden (`client_id=`/`client_secret=`), sonst gelten geteilte Limits. **Aktivieren und testen** ```bash # in /etc/kundencenter/backup.env: BACKUP_REMOTES=nas:kundencenter,gdrive:Backups/kundencenter systemctl start kc-backup && journalctl -u kc-backup -n 30 --no-pager -o cat # Ziele müssen "ok": true zeigen ``` Ein ausgefallenes Ziel lässt den Lauf als Fehler zählen (Meldung), das lokale Backup bleibt erhalten. ## Wiederherstellung (Notfall) 1. Neuer/repariertes Server mit MariaDB, Node und `age`; Kundencenter-Code nach `/srv/kundencenter` (Repo), `pnpm install && pnpm build`. 2. Sicherungsdatei holen (lokal, Ziel) und den **privaten Schlüssel** bereitlegen. 3. Entschlüsseln und entpacken: ```bash age -d -i backup-age-key.txt -o archive.tar.gz kundencenter-DATUM-....tar.gz.age mkdir restore && tar -xzf archive.tar.gz -C restore # enthält db.sql, config/*.env, manifest.json ``` 4. Konfiguration zurück: `cp restore/config/*.env /etc/kundencenter/` (chmod 600), Datenbank und Benutzer anlegen (nur Rechte auf `kundencenter`). 5. Datenbank einspielen: `mysql -u… -p kundencenter < restore/db.sql` 6. Dienste starten (`kc-api`, `kc-worker`, `kc-web`), prüfen: `/v1/ready`, Anmeldung, Übersicht, **Audit-Protokoll → „Integrität prüfen“**. 7. Erwartung: Datenverlust höchstens bis zum letzten Backup (bis zu 24 h), Wiederherstellung ca. 30 Minuten. ## Vor größeren Änderungen Vor Migrationen oder Updates manuell sichern: `systemctl start kc-backup`. Rollback einer fehlerhaften Migration = Wiederherstellung (Abschnitt oben) in eine Wegwerf-Datenbank prüfen, dann produktiv einspielen.