WJ-Kreis-Digital-Standard

Betrieb und Sicherheit

Teil des WJ-Kreis-Digital-Standards. Referenz-Installation: Server "hafen" (WJ Konstanz-Hegau), Stand der Erhebung 2026-08-13. Vorige Kapitel beschreiben, was das System kann. Dieses Kapitel beschreibt, wie es läuft, wenn niemand hinschaut.

Wozu dieses Kapitel

Ein WJ-Kreis hat keinen Admin in Vollzeit. Wer das Digitalressort übernimmt, macht das im Ehrenamt, neben Job und Familie, und gibt das Amt nach ein bis zwei Jahren weiter. Ein System, das wöchentliche Handarbeit braucht, stirbt an der ersten Amtsübergabe. Der Standard setzt deshalb auf drei Prinzipien: Updates laufen automatisch und heilen sich selbst, Secrets liegen nie im Klartext in Dokumenten oder Repos, und das Monitoring ist so schlank, dass es tatsächlich gelesen wird. Alles in diesem Kapitel ist auf der Referenz-Installation im Einsatz oder als Empfehlung markiert.

1. Automatische Updates

1.1 Betriebssystem

Das OS (Ubuntu 24.04 auf der Referenz) spielt Sicherheitsupdates selbstständig ein: unattended-upgrades, bewusst ohne automatischen Reboot. Ein Reboot-Fenster plant ihr manuell, wenn ein Kernel-Update ansteht; alles andere läuft ohne Zutun.

1.2 Nextcloud: das Nachtscript mit Self-Heal

Kernstück des wartungsarmen Betriebs ist nextcloud-autoupdate.sh (im Standard-Repo unter wj/Nextcloud/, installiert als /usr/local/sbin/nextcloud-autoupdate.sh, getriggert über /etc/cron.d/nextcloud-autoupdate täglich um 02:30). Das Script macht drei Dinge:

  1. App-Updates: occ app:update --all aktualisiert alle installierten Apps.
  2. Core-Point-Releases: updater/updater.phar --no-interaction zieht Patch-Versionen im stable-Channel (34.0.1 auf 34.0.2 und so weiter). Major-Upgrades macht es bewusst nicht.
  3. Self-Heal: Nach dem Update prüft es den Zustand und repariert die beiden häufigsten Hänger selbst (Details in Abschnitt 4).

Alles landet im Log /var/log/nextcloud-autoupdate.log, monatlich rotiert per logrotate. Damit das Script ohne Passwort-Eingabe laufen kann, braucht es einen Sudoers-Eintrag, und zwar einen chirurgisch engen: NOPASSWD ausschließlich für das exakte occ-Pattern (sudo -u www-data php /var/www/html/occ ...) und für updater.phar. Alles andere bleibt passwortpflichtig. Das ist die Balance zwischen Automatisierbarkeit und Angriffsfläche.

1.3 Major-Upgrades bleiben Handarbeit

Ein Major-Sprung (etwa Nextcloud 32 auf 33) ist ein geplanter Eingriff, kein Nachtjob. Zwei Lehren aus der Referenz:

Nach jedem Core-Upgrade gehören die Docker-Sidecars (Talk-HPB, Collabora, Whiteboard) einmal durchgestartet: docker pull plus Container-Restart, auch wenn das Image "up to date" meldet. Die Container brauchen eine frische Verbindung zur upgegradeten Nextcloud.

2. Backup-Konzept

Ehrlicher Befund aus der Referenz: Das Backup-Regime ist dort gelebte Praxis, aber noch nicht vollständig als Script im Repo. Belegt sind das Backup-Trio vor Major-Upgrades (Abschnitt 1.3) und ein Cron-Backup des Kompetenz-Hubs alle 3 Stunden. Für den Standard formulieren wir daraus die Soll-Architektur; die Punkte ohne Repo-Artefakt sind als Empfehlung markiert.

Was ein Kreis-Backup abdecken muss:

WasWarumStatus Referenz
Nextcloud-Datenbank (Dump)ohne DB sind die Dateien nur ein Haufen Blobsvor Major-Upgrades belegt; täglich = Empfehlung
Nextcloud data-Verzeichnisdie eigentlichen Dateienwie oben
Nextcloud config.phpInstanz-Identität, Salts, Secretsim Backup-Trio enthalten
n8n /opt/n8n/dataWorkflows und verschlüsselte Credentialsoffen, als Backup-Cron einzurichten
N8N_ENCRYPTION_KEYohne ihn ist das n8n-Backup halb wertlos (siehe Abschnitt 3)liegt root-only in der Compose-Datei, gehört zusätzlich in die sichere Ablage
Docker-Volumes weiterer Dienste (z. B. Demo-Instanz, Analytics)je nach Kreis-Scopeteilweise (Kompetenz-Hub alle 3 h)

Drei Empfehlungen dazu, alle drei ja/nein prüfbar:

  1. Täglicher Backup-Cron für DB-Dump und Data-Verzeichnis, mit Aufbewahrung von mindestens 7 Tagesständen.
  2. Offsite-Kopie: Ein Backup auf demselben Server schützt gegen "occ upgrade ging schief", aber nicht gegen "Server weg". Hetzner-Storage-Box, ein zweiter Server oder ein verschlüsseltes Ziel beim Kreis reichen.
  3. Restore-Probe einmal pro Amtsjahr: Ein Backup, das nie zurückgespielt wurde, ist eine Hoffnung, kein Backup. Die Demo-Replika-Mechanik (Kapitel Rollout-Runbook) eignet sich als Restore-Ziel.

3. Secrets-Handling: das Vault-Prinzip

Die eiserne Regel des Standards: Kein Secret-Wert steht jemals im Klartext in einem Dokument, einem Repo oder einer Chat-Nachricht. Dokumentiert werden nur Key-Namen, Ablageorte und Platzhalter wie <SIGNALING_SECRET>. Auf der Referenz ist das durchgezogen; so sieht es konkret aus:

Ein Wert verdient besondere Aufmerksamkeit: der N8N_ENCRYPTION_KEY. Er verschlüsselt alle in n8n gespeicherten Credentials. Geht er verloren, sind sämtliche Zugänge unentschlüsselbar und müssen neu angelegt werden (die Workflows selbst bleiben intakt). Er liegt auf der Referenz root-only in der Compose-Datei; sichert ihn zusätzlich an einem zweiten sicheren Ort, getrennt vom Server.

Führt außerdem ein Secrets-Register: eine Tabelle mit Key-Namen und Ablageort je Secret, ohne Werte. Das Register darf in die Kreis-Doku, denn es verrät nichts, macht aber jede Amtsübergabe und jede Rotation zu einer Abhak-Übung statt einer Schatzsuche. Das Muster der Referenz steht im Inventar (meta/inventory-knowledge.md, Abschnitt 9).

Zum Schluss die Sonderfalle VereinOnline: Das VO-Token-Format ist A/<username>/<md5(passwort)>. MD5 ist kryptografisch gebrochen, das ist VO-Stand der Technik und nicht von euch änderbar. Konsequenz: langes Zufallspasswort für die Service-User, Transport ausschließlich über HTTPS. Und: Ein ungültiges VO-Token erzeugt keinen Fehler, sondern einen stillen Fallback auf anonyme Rechte. Write-Workflows sollten deshalb die Antwort auf den angemeldeten Usernamen prüfen, statt Erfolg anzunehmen.

4. Wenn der Wartungsmodus hängt: das Self-Heal-Pattern

Das häufigste Nextcloud-Betriebsproblem sieht so aus: Ein Update wird angestoßen (Web-Updater, Timeout, Verbindungsabbruch), bricht mittendrin ab, und die Instanz bleibt im Wartungsmodus stehen. Für alle Mitglieder ist "die Cloud kaputt", tatsächlich fehlen genau zwei Kommandos. Auf der Referenz ist genau das am 2026-08-13 passiert (abgebrochener Web-Updater beim Sprung auf 34.0.2), und aus dem Vorfall wurde das Self-Heal im Nachtscript.

Das Muster, erst als Handgriff, dann als Automatik:

Manuell (wenn ihr es live vor euch habt):

occ status                      # zeigt maintenance: true und ggf. needsDbUpgrade
occ upgrade                     # zieht eine hängende DB-Migration zu Ende
occ maintenance:mode --off      # schaltet den Wartungsmodus ab

Wichtig ist die Reihenfolge: erst prüfen, ob eine DB-Migration aussteht (needsDbUpgrade: true in occ status), und die zuerst durchlaufen lassen. Den Wartungsmodus einfach abzuschalten, während die Datenbank halb migriert ist, verschiebt das Problem nur.

Automatisch: Das Nachtscript prüft nach jedem Lauf exakt diese beiden Zustände. Meldet occ status ein needsDbUpgrade: true, läuft occ upgrade nach. Steht der Maintenance-Mode noch, obwohl kein Upgrade mehr aussteht, schaltet das Script ihn ab. Damit heilt sich die häufigste Störung innerhalb von 24 Stunden selbst, ohne dass jemand gerufen wird. Wer nachts um 02:30 nicht warten will, führt das Script einfach manuell aus; es ist idempotent.

Die Meta-Lektion für euer Digitalressort: Jede Störung, die zweimal auftritt, gehört als Erkennung plus Reparatur ins Nachtscript, nicht ins Gedächtnis des aktuellen Amtsinhabers.

5. Monitoring-Minimum

Ihr braucht kein Grafana-Dashboard. Ihr braucht Antworten auf vier Fragen, und zwar mit minimalem Aufwand:

  1. Läuft die Cloud? Empfehlung: ein externer Uptime-Check auf https://<eure-domain>/status.php (der Endpoint liefert JSON mit "installed":true und der Version, das Bootstrap-Script der Replika nutzt ihn genauso). Externe Gratis-Dienste oder ein Cron auf einem anderen Server reichen.
  2. Liefen die Updates durch? Ein Blick in /var/log/nextcloud-autoupdate.log. Empfehlung als Ausbaustufe: das Script bei Fehlern eine Nachricht in einen Talk-Kanal schicken lassen, das Muster dafür (Talk-Chat-API mit Bot-User) existiert in den Flow-Workflows bereits.
  3. Geht dem Server etwas aus? Die Nextcloud-App serverinfo (auf der Referenz aktiv) zeigt RAM, Platte und Last direkt in der Admin-Oberfläche. Auf der Referenz sind nach dem Aufbau der Demo-Replika noch 2,7 GB RAM frei, der Server ist damit voll; genau solche Grenzen muss der Kreis kennen, bevor er den nächsten Dienst dazustellt.
  4. Sind die Container gesund? docker ps zeigt die Health-Stati (HPB und Whiteboard laufen auf der Referenz mit Healthcheck). Für den Talk-HPB gibt es zusätzlich einen echten Funktionstest: curl https://<domain>/standalone-signaling/api/v1/welcome muss antworten.

Dazu gehören die Bordmittel, die ohnehin installiert sind und im Standard-App-Set bleiben: logreader (Nextcloud-Log in der UI), updatenotification (Hinweis auf anstehende Major-Versionen), admin_audit (wer hat was geändert), suspicious_login und bruteforcesettings (Login-Anomalien). Einmal pro Monat fünf Minuten in die Admin-Übersicht zu schauen ist das ganze Monitoring-Ritual; alles Dringende soll euch erreichen, statt gefunden werden zu müssen.

6. Sicherheits-Baseline

Die Grundhärtung der Referenz, als Standard übernehmbar:

7. Update-Gotchas bei geteilten Containern

Sobald ein Server mehr als eine Nextcloud bedient (Co-Tenant-Modell, Kapitel Rollout-Runbook), teilen sich die Instanzen Collabora und den Talk-HPB. Das spart Ressourcen, schafft aber zwei Update-Fallen, die beide schon real zugeschnappt haben beziehungsweise im Blueprint dokumentiert sind:

Talk-HPB (aio-talk-Container): Der Container generiert seine Signaling-Config bei jedem Start im Entrypoint neu, fest auf eine Domain. Multi-Tenant funktioniert deshalb über ein gepatchtes Startskript, das als read-only Bind-Mount über /start.sh gelegt wird (Overlay, auf der Referenz seit 2026-08-13 aktiv, Original gesichert). Daraus folgen zwei Pflichten bei jedem Image-Update:

  1. Den Overlay-Mount beim Recreate behalten. Wer den Container ohne den -v ...:/start.sh:ro-Mount neu erstellt, trennt kommentarlos die zweite Instanz vom HPB.
  2. Das Startskript aus dem neuen Image frisch extrahieren und neu patchen (docker run --rm <image> cat /start.sh, dann Patch anwenden). Wer den alten Patch weiterverwendet, pinnt veraltete Upstream-Logik fest.

Dazu das allgemeine HPB-Update-Muster: env-file aus dem alten Container übernehmen (Secrets bleiben serverseitig), Ports 3478 tcp/udp plus 127.0.0.1:8081 setzen, und danach beide Instanzen per curl .../standalone-signaling/api/v1/welcome verifizieren. Eine bekannte, harmlose Warnung nach Updates: "Server unterstützt nicht alle Funktionen dieser Talk-Version" heißt nur, dass der Signaling-Server im Image der spreed-App hinterherhinkt; nur Admins sehen das, der Fix kommt mit dem nächsten Image-Release.

Collabora: Weitere Instanzen hängen per aliasgroupN-Env am selben Container. Beim Update oder Recreate müssen alle aliasgroup-Einträge im Env-File erhalten bleiben, sonst verliert eine der Instanzen ihr Office. Nach jedem Recreate beide (alle) angebundenen Nextclouds kurz prüfen: ein Dokument öffnen genügt.

Die Merkregel hinter beiden Fällen, wortwörtlich aus dem Blueprint der Referenz: Generiert ein Container seine Config im Entrypoint aus Env-Variablen, patcht man den Entrypoint per read-only Bind-Mount, nie die generierte Config im laufenden Container. Und generell gilt für geteilte Container: Ein Update betrifft immer alle angebundenen Instanzen gleichzeitig, also nach jedem Update jede Instanz einzeln verifizieren, nicht nur die Haupt-Instanz.

Checkliste

Einmalig bei der Einrichtung:

Wiederkehrend (monatliches 15-Minuten-Ritual):

Bei jedem Image-Update geteilter Container:

Bei Major-Upgrades:

Referenz KNH

So läuft es bei Konstanz-Hegau konkret (Stand 2026-08-13):

BausteinUmsetzung auf hafen
OS-Updatesunattended-upgrades auf Ubuntu 24.04, ohne Auto-Reboot
NC-Updates/usr/local/sbin/nextcloud-autoupdate.sh, täglich 02:30 via /etc/cron.d/nextcloud-autoupdate, Log /var/log/nextcloud-autoupdate.log, logrotate monatlich
Self-Healim Nachtscript: needsDbUpgrade löst occ upgrade aus, hängender Maintenance-Mode wird abgeschaltet; Anlassfall war der abgebrochene Web-Updater beim Sprung auf 34.0.2 am 2026-08-13
SudoersNOPASSWD nur für das occ-Pattern und (seit 2026-08-13) updater.phar
BackupsBackup-Trio vor Major-Upgrades unter /var/backups/nextcloud-pre<major>/; Kompetenz-Hub alle 3 h per Cron; täglicher NC-Backup-Cron und n8n-Backup-Cron stehen als offene Punkte
Secretsserverseitig generierte .env-Dateien (root, chmod 600), env-file-Übernahme bei Container-Recreates, N8N_ENCRYPTION_KEY root-only in /opt/n8n/, Secrets-Register im Inventar
Service-AccountsVO: der Lese-User (read), der Write-User (Anmeldungen), der Event-User (Event-CRUD); NC: wj-bot in Gruppe Automation, App-Token, keine User-Create-Rechte
Monitoringserverinfo, logreader, updatenotification, admin_audit, suspicious_login, bruteforcesettings aktiv; Container-Healthchecks für HPB und Whiteboard; RAM-Reserve nach Demo-Aufbau 2,7 GB (Server voll)
2FATOTP + WebAuthn + Backup-Codes installiert, Opt-in; Vorstands-Rollout mit fertiger Anleitung ist der letzte offene Follow-up
Geteilte ContainerTalk-HPB multi-tenant per start.sh-Overlay (backend-1 hafen, backend-2 wjhcloud-Demo, Original als hpb-start-orig.sh gesichert); Collabora bedient beide NCs per aliasgroup2
Netzwerkalles auf 127.0.0.1 hinter Apache + Let's Encrypt, offen nur 3478 (TURN/STUN); SSH key-based ED25519

Offene Punkte der Referenz, die ein nachbauender Kreis von Tag 1 an besser machen kann: täglicher Backup-Cron mit Offsite-Ziel, n8n-Backup, 2FA-Pflicht ab Einrichtung statt nachträglichem Rollout, und im HPB-Overlay ein eigener Secret-Eintrag pro Backend.

← 05 AutomatisierungenWeiter: 07 Rollout →