Echte Umlaute in allen Texten der Oberflaeche und in den Markdown-Dateien. Die Einbindung von Dateifreigaben haengt jetzt an der Sitzung: wird sie widerrufen oder laeuft sie ab, verschwinden die Freigaben mit ihr. Neu einstellbar ist die automatische Abmeldung bei Leerlauf (Vorgabe 30 Minuten). Ein Geraet, das nicht antwortet, bietet nur noch "Einschalten (PoE)" an -- Neustart ueber SSH oder RPC braucht ein erreichbares Geraet. Der Zeitgeber der naechsten Pruefung und die Restlaufzeit der Lizenz stehen jetzt oben in der Kopfzeile; der doppelte Knopf darunter ist weg. Millisekunden werden ab einer Sekunde als Sekunden und ab einer Minute als m:ss dargestellt. Ausserdem: Release-Tarball nicht mehr im Repository -- er haengt am Release. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
10 KiB
Betrieb
Dieses Dokument richtet sich an die Person, die die Anlage installiert, aktualisiert und im Fehlerfall wieder zum Laufen bringt. Es beschreibt, was auf dem Host tatsächlich passiert -- nicht, wie die Oberfläche bedient wird.
1. Was wo liegt
| Zweck | Pfad |
|---|---|
| Anwendung (Code, venv, statische Dateien) | /srv/<name>/ |
| Instanzdaten (Datenbank, Schlüssel, Lizenz) | /srv/<name>/data/ |
| Protokolle | /var/log/<name>/ |
| Umgebungsdatei | /etc/tesm/<name>.env |
| Zertifikate (selbstsigniert) | /etc/tesm/certs/<name>/ |
| nginx-Site | /etc/nginx/sites-available/<name> |
| systemd-Unit | /etc/systemd/system/<name>.service |
| Privilegierter Helfer | /usr/local/lib/tesm/tesm-helper |
| Verwaltungswerkzeug | /usr/local/bin/<name>-admin |
<name> ist tesm bzw. tesm-license -- oder, bei einer zusätzlichen
Instanz, tesm-<instanz>. Dieser Name (der SITE_KEY) benennt alles, was
ausserhalb von /srv/<name> liegt. Deshalb können zwei Installationen
derselben Anwendung nebeneinander laufen, ohne sich gegenseitig die
nginx-Site, die netplan-Datei oder das Sitzungscookie zu überschreiben.
Alles, was ein Mensch verlieren würde, liegt unter data/. Das Verzeichnis
wird von install.sh nie angefasst.
2. Installation
sudo bash deploy/install.sh --app tesm
sudo bash deploy/install.sh --app tesm-license
Wichtige Optionen:
| Option | Wirkung |
|---|---|
--https |
Port 443 mit TLS, Port 80 leitet dorthin um. Ohne --domain entsteht ein selbstsigniertes Zertifikat. |
--domain <name> |
Öffentlicher Name. Setzt server_name; die Site ist dann nicht mehr die Vorgabe-Site. |
--acme-email <a> |
Erst zusammen mit --domain wird ein Let's-Encrypt-Zertifikat angefordert (und HSTS gesetzt). Ohne die Adresse bleibt es selbstsigniert -- interne Namen wie lizenz.firma.local kann keine CA bestätigen. |
--instance <name> |
Zusätzliche Instanz neben der Hauptinstallation. |
--port / --http-port / --https-port |
Abweichende Ports (nur für Testinstanzen sinnvoll). |
--skip-packages |
Keine Systempakete installieren. |
Danach:
sudo -u tesm tesm-admin create-admin
Beim Lizenzserver zusätzlich, in dieser Reihenfolge:
sudo -u tesm-license tesm-license-admin init-key # Signaturschlüssel -- sofort sichern!
sudo -u tesm-license tesm-license-admin bootstrap # eigene Master-Lizenz
sudo -u tesm-license tesm-license-admin create-admin
Der Signaturschlüssel ist nicht wiederherstellbar. Geht
data/master_signing_key.jsonverloren, ist keine ausgestellte Lizenz mehr prüfbar. Sichern Sie ihn getrennt vom Server.
Zwei Anwendungen auf einem Host
Beide wollen Port 80 und 443. nginx unterscheidet sie am Namen:
sudo bash deploy/install.sh --app tesm --https
sudo bash deploy/install.sh --app tesm-license --https --domain lizenz.firma.local
Die Installation ohne Domain wird zur Vorgabe-Site (default_server) und
beantwortet alles, was zu keinem Namen passt. Zwei namenlose Sites auf
demselben Port weist nginx ab -- richtig so, und beim Übernehmen sofort
sichtbar.
3. Aktualisierung
sudo bash deploy/install.sh --app tesm
Derselbe Befehl. Das Skript erkennt an der vorhandenen Datenbank, dass es eine Aktualisierung ist, und tut dann zusätzlich:
- Vollständige Sicherung nach
/srv/<name>-backup-<zeitstempel>-- unabhängig davon, ob sich das Schema geändert hat. - Dateiabgleich;
data/bleibt unangetastet. - Schema-Migrationen beim Start (versioniert, mit Prüfsumme).
- Gesundheitsprüfung. Antwortet die Anwendung nicht, wird der alte Stand
automatisch zurückgeholt; die fehlgeschlagene Version bleibt unter
/srv/<name>-failed-<zeitstempel>zur Analyse liegen.
Eine bereits eingerichtete HTTPS-Konfiguration bleibt erhalten, auch ohne
--https.
4. HTTPS
Der Zielzustand ist immer: Port 443 mit TLS, Port 80 leitet um, ausser dem ACME-Pfad.
Drei Wege dorthin:
a) Bei der Installation -- siehe oben, --https.
b) Nachträglich über die Kommandozeile:
sudo -u tesm tesm-admin web-setup --https --self-signed --apply
sudo -u tesm tesm-admin web-setup --https --domain tesm.firma.de \
--acme --acme-email it@firma.de --hsts --apply
--print-config zeigt die Datei, ohne etwas zu schreiben.
c) In der Oberfläche unter Einstellungen -> Webserver und TLS.
Danach muss COOKIE_SECURE in /etc/tesm/<name>.env auf 1 stehen (alle drei
Wege erledigen das selbst) und der Dienst neu gestartet werden.
Die Site-Datei wird immer neu erzeugt
Sie ist kein Ort für Handarbeit. Jede Übernahme schreibt sie vollständig aus der Vorlage neu. Was früher von Hand hineingeschrieben wurde -- Domain, Ports, Zertifikatspfade, HSTS, Upload-Grenze -- ist heute Einstellung in der Anwendung.
Der Grund steht im Vorgängerprojekt: dort wurde die Datei nur angelegt, wenn
sie fehlte. Ein einmal falscher alias-Pfad überlebte dadurch jahrelang jedes
Update, und die Oberfläche kam die ganze Zeit ohne Design.
Selbstsigniert oder Let's Encrypt?
- Öffentlich erreichbar, echter DNS-Name: Let's Encrypt. Nur dann ist HSTS sinnvoll.
- Geschlossenes Netz: selbstsigniert. Browser zeigen eine Warnung, die
Verbindung ist trotzdem verschlüsselt und das Sitzungscookie darf
Securetragen. HSTS hier nicht einschalten -- der Browser merkt sich die Vorgabe monatelang und die Warnung lässt sich dann nicht mehr wegklicken.
Die Erneuerung von Let's Encrypt läuft über certbot certonly --webroot
(bewusst nicht über das nginx-Plugin, das die erzeugte Site umschreiben
würde). Der ACME-Pfad bleibt auch bei aktiver Umleitung erreichbar.
5. Dienste
systemctl status tesm.service # Weboberfläche (gunicorn)
systemctl status tesm-monitor.service # Überwachungsschleife (nur TESM)
systemctl status tesm-license.service
journalctl -u tesm -n 100 -f
Die Units laufen unprivilegiert (User=tesm) mit
NoNewPrivileges, ProtectSystem=strict, PrivateTmp und einer engen
RestrictAddressFamilies-Liste. Schreibrechte gibt es nur auf /srv/<name>/data
und /var/log/<name>.
6. Root-Rechte
Die Anwendung hat keine. Alles, was Root braucht, geht durch einen Pfad:
/usr/local/lib/tesm/tesm-helper <verb> [argumente]
Der Helfer gehört root, ist per sudoers ausschliesslich für genau diesen
Pfad mit NOPASSWD freigegeben und prüft jedes Argument gegen eine
Positivliste. Er reicht nie etwas an eine Shell weiter (kein eval, kein
sh -c).
Verben ansehen:
sudo /usr/local/lib/tesm/tesm-helper
grep -n ')$' /usr/local/lib/tesm/tesm-helper
Regel für Änderungen: Jedes neue Verb braucht eine Argumentprüfung.
tests/test_repo_hygiene.py erzwingt, dass jedes der Anwendung bekannte Verb
im Helfer vorkommt und dass jede Pfadprüfung .. abweist.
7. Sicherung und Wiederherstellung
In der Oberfläche unter Sicherung -- verschlüsselte Ausfuhr (Argon2id + AES-256-GCM) mit einem selbst gewählten Kennwort. Der Import zeigt zuerst eine Vorschau, bevor irgendetwas geschrieben wird.
Auf dem Host reicht:
sudo systemctl stop tesm
sudo tar -czf /root/tesm-data-$(date +%F).tar.gz -C /srv/tesm data
sudo systemctl start tesm
Unverzichtbar:
data/app.db-- alle Datendata/secret.key-- ohne sie sind alle Sitzungen ungültigdata/data.keys-- ohne sie sind alle gespeicherten Geheimnisse verlorendata/license.jsonunddata/license_key.json- Lizenzserver zusätzlich:
data/master_signing_key.json
8. Wenn etwas nicht geht
Die Anwendung antwortet nicht.
journalctl -u tesm -n 200 --no-pager
curl -s http://127.0.0.1:5000/gesundheit
Antwortet gunicorn, aber der Browser nicht, liegt es an nginx.
nginx lässt sich nicht neu laden.
sudo nginx -t
Die Übernahme aus der Anwendung nimmt eine abgelehnte Konfiguration selbst
zurück. Eine von Hand bearbeitete Datei tut das nicht -- in dem Fall hilft
install.sh, das eine unbrauchbare Site durch die Vorlage ersetzt.
Anmeldung schlägt ohne Fehlermeldung fehl.
Fast immer COOKIE_SECURE=1 ohne HTTPS. Der Browser bekommt dann ein Cookie,
das er über HTTP nie zurücksendet.
grep COOKIE_SECURE /etc/tesm/tesm.env
"Die Anfrage kam von einer fremden Herkunft (Origin/Referer)."
Der Reverse Proxy reicht den Host falsch durch. In der Site-Datei muss
proxy_set_header Host $http_host; stehen -- nicht $host, das verwirft
den Port.
Statische Dateien fehlen, die Oberfläche ist unformatiert.
grep alias /etc/nginx/sites-available/tesm
ls /srv/tesm/static /srv/tesm/static-core
Beide alias-Pfade müssen in das Installationsverzeichnis zeigen.
Zwei Instanzen stören sich.
SITE_KEY in beiden /etc/tesm/*.env vergleichen -- er muss sich
unterscheiden. Sonst teilen sich beide nginx-Site und Sitzungscookie.
Die Wartung meldet "Der SSH-Host-Schlüssel ist unbekannt". Kein Fehler, sondern die Absicht: ein Hintergrundauftrag darf keinen fremden Schlüssel akzeptieren. Die Freigabe erfolgt von Hand, in zwei Schritten, auf der Detailseite des Geräts (Clients -> Gerät -> SSH-Host-Schlüssel): erst Auslesen, dann den Fingerprint mit einer unabhängigen Quelle vergleichen, dann Freigeben. Die Wartungsübersicht zeigt in einer eigenen Spalte, für welche Geräte das noch offen ist. Für Switche liegt dieselbe Freigabe auf der Switch-Detailseite.
Der Schlüssel wird nach IP und Port gespeichert, nicht nach Name -- TESM verbindet sich immer über die hinterlegte IP-Adresse. Ändert sich die IP eines Geräts, ist der Schlüssel erneut freizugeben.
Die Prüfkette des Änderungsprotokolls ist gebrochen. Unter Diagnose sichtbar. Das Protokoll ist verkettet gehasht; ein Bruch heisst, dass jemand direkt in die Datenbank geschrieben hat. Der Eintrag, ab dem es nicht mehr stimmt, wird genannt.
9. Zurück auf eine ältere Version
sudo systemctl stop tesm
sudo mv /srv/tesm /srv/tesm-kaputt
sudo cp -a /srv/tesm-backup-<zeitstempel> /srv/tesm
sudo systemctl start tesm
Schema-Migrationen laufen nur vorwärts. Ein Rücksprung über eine Schema-Änderung hinweg braucht deshalb auch die Datenbank aus der Sicherung -- genau das liegt im Backup-Verzeichnis.