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

Alltag
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.

BereichRateKörper
Kontoanlage5 pro Stunde2 MB
Anmeldung, Kopplung10 pro Minute2 MB
Kopplungsstatus (wird gepollt)120 pro Minute2 MB
Wiederherstellung5 pro Stunde, zusätzlich 5 pro Konto2 MB
Rotation120 pro Minute16 MB
alles andere120 pro Minute2 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.

Nächtlich per cron
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

Aktualisieren
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:

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.