Betrieb und Wartung
Der Server ist absichtlich langweilig: ein Node-Prozess unter systemd, eine MariaDB, nginx davor. Kein Docker, kein Runner, kein fremder Dienst, der mitreden muss.
Dienst
systemctl status tessera
systemctl restart tessera
journalctl -u tessera -f
Der Prozess läuft als Systembenutzer tessera ohne Shell
und bindet auf 127.0.0.1. Erreichbar ist er nur über den
Reverse Proxy.
Ratenlimits
Zwei Ebenen: nginx riegelt ab, bevor der Node-Prozess überhaupt erreicht wird, die Anwendung noch einmal darunter.
| Bereich | Rate | Körper |
|---|---|---|
| Kontoanlage | 5 pro Stunde | 2 MB |
| Anmeldung, Kopplung | 10 pro Minute | 2 MB |
| Kopplungsstatus (wird gepollt) | 120 pro Minute | 2 MB |
| Wiederherstellung | 5 pro Stunde, zusätzlich 5 pro Konto | 2 MB |
| Rotation | 120 pro Minute | 16 MB |
| alles andere | 120 pro Minute | 2 MB |
Steht nginx davor, muss TESSERA_TRUST_PROXY=true gesetzt
sein — sonst zählt die Anwendung alle Anfragen auf die Adresse des
Proxys und sperrt beim ersten Andrang alle aus.
Sicherung
Gesichert wird die Datenbank; sie enthält ausschließlich Ciphertext. Ein Backup ist damit auch dann unkritisch, wenn es an einem weniger geschützten Ort liegt — ohne den Vault Key ist es eine Sammlung Zufallsbytes.
17 3 * * * /usr/local/bin/tessera-backup
Was ein Backup nicht rettet: einen verlorenen Wiederherstellungscode bei gleichzeitig verlorenen Geräten. Der Server kann nichts entschlüsseln, auch nicht aus einem Backup heraus.
Updates
git pull
sudo ./deploy/install.sh # derselbe Aufruf wie bei der Erstinstallation
Das Skript spiegelt den Serverstand, installiert Abhängigkeiten aus dem
Lockfile, spielt ausstehende Migrationen ein und startet den Dienst
neu. Bestehende Konfiguration in /etc/tessera/env bleibt
unangetastet.
Schema-Migrationen
MariaDB kann DDL nicht zurückrollen. Deshalb gelten zwei Regeln ohne Ausnahme:
-
Jede Migration muss bei erneutem Lauf zu Ende laufen —
IF NOT EXISTSüberall. - Jede Schemaänderung bringt ein dokumentiertes Downgrade-Szenario mit: Was passiert, wenn eine ältere Version wieder läuft?
Für das Client-Schema kommt eine dritte Frage dazu: Was macht ein älteres Gerät mit einem neueren Payload? Additive Felder verlieren, wenn ein altes Gerät den Record schreibt — es kennt sie nicht und schreibt sie nicht zurück.
Wie weit das reicht, hängt am Feld. Ein verlorener Schalter ist
ärgerlich; beim Protokoll eines Hosts (Client-Schema 3) ändert der
Host seine Art: Ein älteres Gerät, das einen Remote-Desktop-Host
zurückschreibt, macht daraus einen SSH-Host. Deshalb gilt dort
ausdrücklich: erst alle Geräte aktualisieren, dann anlegen. Die
Einstellungen innerhalb von rdp sind davon
ausgenommen — dort bleiben unbekannte Schlüssel erhalten.
Warum MariaDB und nicht SQLite
Der Server schreibt aus mehreren Verbindungen gleichzeitig, und die
Rotation läuft als eine große Transaktion über alle Records. Genau das
ist die Stelle, an der eine dateibasierte Datenbank unter Last
unangenehm wird. Alle Tabellen sind InnoDB und
utf8mb4_bin.
Eine case-insensitive Kollation auf einer ID-Spalte ist eine Sicherheitslücke, keine Bequemlichkeit: Zwei IDs, die sich nur in der Groß- und Kleinschreibung unterscheiden, wären dieselbe.
Überwachen
GET /healthz antwortet mit
{"status":"ok"} — bewusst ohne jede Zahl über Konten oder
Datensätze. Für mehr reicht ein Blick ins Journal; der Server loggt
strukturiert und niemals Schlüsselmaterial.