This repository has been archived on 2026-09-17. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
nixos-config/docs/research/full-system-aufit.md
pijukka 314f56b956 docs: recategorize full-system audit as a research intent
Was created under docs/intent/, which only ever reaches the Operator
(direct_builder/split/needs_human -- no "send to Researcher" option
exists there at all). The Operator picked direct_builder for a
read-only audit needing systemd/journal/network access; Builder
correctly refused (scoped git-only Bash, no shell/journal/network
access) and recommended the Researcher role by name. Moved to
docs/research-intent/, re-ran through Request Research, and committing
its now-completed docs/research/full-system-aufit.md alongside it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016w25covboHfcYuLXBAvX3g
2026-09-11 17:32:07 +02:00

164 lines
24 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Full-System-Audit: NixOS-Plattform (blunix / pinix / tnix)
**Datum:** 2026-09-11
**Scope:** Read-only Audit von Repository (`/home/drone/nixos-config`, Branch `dev`, HEAD detached), Runtime-Zustand auf `blunix` (lokale Shell, systemd, Journal, Netzwerk, HTTP), sowie extern erreichbare Endpunkte unter `*.0ff.space`.
**Methode:** Repository-Lektüre (Nix-Konfiguration, Git-Historie), lokale Diagnosebefehle auf blunix (systemctl, journalctl, ss, df/du, tailscale status), sowie HTTP-Prüfungen gegen öffentlich exponierte Endpunkte über einen bereits im Nix-Store vorhandenen `curl`-Build (kein neuer Build/keine Zustandsänderung). Kein SSH auf pinix/tnix, kein `nixos-rebuild`, keine schreibenden Aktionen.
## Executive Summary
1. **Kritischer Vorfall bestätigt:** blunix ist mit 96 % Diskbelegung (1,5 GB frei von 37 GB) faktisch am Limit. Am 10.09. führte das tatsächlich zu Ausfällen (Forgejo-Dump, Prosody Push-Notifications, DHCP-Lease-Schreibvorgang schlugen mit „No space left on device" fehl). Ursache: ~208 `nixos-rebuild switch`-Läufe und 34 System-Generationen in weniger als 48 Stunden (automatisierte Builder-Pipeline), während GC nur wöchentlich mit 30-Tage-Retention läuft.
2. **pinix ist seit ca. 1 Tag über Tailscale nicht erreichbar** (`tailscale status`: „offline, last seen 1d ago"). Das erklärt gleichzeitig mehrere scheinbar unabhängige Symptome: Timeouts auf `board.0ff.space`, `social.0ff.space`, `phanpy.0ff.space`, `sound.0ff.space`, `calendar.0ff.space` sowie wiederkehrende Forgejo-Webhook-Fehler gegen `100.64.0.3:9000` (pinix' Tailnet-IP).
3. Der **Codeberg-Push-Mirror schlägt seit Tagen zyklisch alle paar Stunden fehl**, weil der Mirror versucht, den Branch `master` auf Codeberg zu löschen (lokal existiert kein `master` mehr, nur `dev`/`production`), Codeberg das aber als aktuellen Default-Branch ablehnt.
4. Auf blunix liegt ein **verwaistes 117 MB großes `/var/lib/gotosocial`-Verzeichnis**, obwohl GoToSocial laut Repo ausschließlich auf pinix läuft — vermutlich Rückstand einer Host-Migration, verschärft den Diskdruck unnötig.
5. **LLDAP** (Admin-Verzeichnisdienst) ist öffentlich unter `lldap.0ff.space` ohne zusätzliche Traefik-Middleware (kein `basicAuth`, anders als z. B. das Traefik-Dashboard) erreichbar (HTTP 200 auf Login-Seite) — vergrößert die Angriffsfläche für den zentralen Auth-Verzeichnisdienst.
## Audit Coverage
**Untersucht:**
- Repository-Struktur, `flake.nix`, Host-Configs (`hosts/blunix`, `hosts/pinix`, `hosts/tnix`, `hosts/globalServices`), Firewall-/Traefik-/GC-Konfiguration
- Git-Historie (letzte ~30 Commits), Branch-/Remote-Zustand
- systemd: alle Units, Failed-Units (keine), Restart-Zähler, laufende vs. nicht-laufende Services, Timer (restic, forgejo-dump, nix-gc)
- Journal: `journalctl -p err` über die letzten Tage, gezielte Suche nach wiederkehrenden Mustern (Forgejo, Prosody, SSH, dhcpcd)
- Disk-/Speicherzustand (`df -h`, `du` auf `/var/lib/*`, `/nix/store`, `/home`, journal disk usage), Nix-Generationenverlauf
- Netzwerk: offene Ports (`ss -tlnp`), Firewall-Regeln aus dem Repo (`allowedTCPPorts`, `trustedInterfaces`), Tailscale-Peer-Status
- HTTP: Live-Check mehrerer extern gerouteter Endpunkte (`git`, `lldap`, `traefik`, `board`, `social`, `phanpy`, `sound`, `data`, `hdm`, `head`, `calendar`) via bereits gebautem `curl`
- Backup-Kette: restic-Timer und letzte drei Läufe, Forgejo-Dump-Timer und letzter Lauf
**Nicht untersucht / eingeschränkt:**
- **Kein Zugriff auf pinix oder tnix** (weder SSH noch Shell) — alle Aussagen zu diesen Hosts stammen ausschließlich aus Repo-Konfiguration und indirekten Beobachtungen von blunix aus (Traefik-Timeouts, Tailscale-Status, Webhook-Fehler). Der tatsächliche Zustand von pinix (läuft es noch? Netzwerkproblem oder Host down?) bleibt ungeklärt.
- Keine Web-UI-Funktionsprüfung mit echtem Login (Board, Kanboard, Mastodon-Frontend etc.), da das die Sandbox-Vorgabe „keine Formulareingaben/Aktionen" verletzen würde und ohnehin die Backends über pinix nicht erreichbar waren.
- Detailinhalt von `/var/lib/forgejo`, `/var/lib/mysql/*`, `/var/log/fail2ban`, `/var/lib/tailscale` etc. war aus Permission-Gründen (kein sudo im Runtime-Pfad dieser Rolle) nicht lesbar; Aussagen zu diesen Komponenten stützen sich auf öffentlich lesbare Metadaten (Verzeichnisgröße von außen, systemctl-Status).
- Kein `nix flake check` / `nix eval` durchgeführt (für diesen Auftrag nicht notwendig gewesen); keine Bewertung der Nix-Ausdrucks-Korrektheit über die gelesenen Dateien hinaus.
- Keine tiefere Analyse von `agents/` (Board-Automatisierung, Codex/Claude-Runner) über das hier relevante Maß hinaus — der Job, der diesen Audit ausführt, läuft selbst als `board-agent-worker.service`-Kindprozess; das wurde nur am Rande beobachtet, nicht separat auditiert.
- Die genannten 5 SSH-`kex_exchange_identification`-Fehler/Tag wurden nicht tiefer untersucht (typisches Internet-Hintergrundrauschen von Portscannern); fail2ban-Jail-Details konnten mangels `fail2ban-client` im PATH nicht abgefragt werden, nur `systemctl is-active fail2ban` (aktiv).
## Findings
### F1 — Disk-Auslastung auf blunix kritisch, bereits mit realem Ausfall (Critical)
**Komponenten:** blunix Root-Filesystem, Nix-Store, `nix.gc` (`hosts/nix-gc.nix`), automatisierte Rebuild-Pipeline (`agent-codex/deploy_runner.py`), Forgejo, Prosody, dhcpcd
**Beobachtung:** `df -h` zeigt 96 % Belegung (34G/37G, 1,5G frei). `/nix/store` allein belegt 25G. Zwischen dem 09.09. 22:49 und dem 11.09. 16:40 wurden 34 System-Generationen erzeugt (`system-471-link` … `system-504-link`), `journalctl` zählt 208 Aktivierungen von `nixos-rebuild-switch-to-configuration.service` in 3 Tagen.
**Evidenz:**
```
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/pool-root 37G 34G 1.5G 96% /
Sep 10 04:31:02 blunix forgejo[1636407]: Failed to create temporary directory: ... no space left on device
Sep 10 04:31:02 blunix systemd[1]: Failed to start forgejo dump.
Sep 10 00:59:42 blunix prosody[683999]: datamanager: Unable to write to cloud_notify storage ('No space left on device')
Sep 10 05:00:07 blunix dhcpcd[450984]: dhcp_writefile: ... No space left on device
```
**Erwarteter Zustand:** Ausreichend Puffer entsprechend der in `hosts/nix-gc.nix` dokumentierten Analyse (`docs/intent/nix-gc-plattform.md`, min-free 1GiB/max-free 3GiB), keine anwendungsseitigen Fehler durch Plattenmangel.
**Tatsächlicher Zustand:** Trotz aktivierter `min-free`/`max-free`-Settings (verifiziert in `/etc/nix/nix.conf`) reicht die inkrementelle Garbage Collection nicht aus, weil `nix.gc` nur wöchentlich mit `--delete-older-than 30d` läuft — bei 200+ Rebuilds/3 Tage bleiben praktisch alle Generationen (und ihre GC-Roots) für Wochen erhalten.
**Vermutete Ursache:** Hohe Rebuild-Kadenz der Board-/Builder-Automatisierung kombiniert mit einer GC-Policy, die auf gelegentliche manuelle Rebuilds ausgelegt war, nicht auf mehrfach-stündliche automatisierte Deploys.
**Mögliche Auswirkungen:** Wiederkehrende Datenverlust-nahe Situationen (fehlgeschlagene Backups/Dumps), Instabilität weiterer schreibender Dienste, im Extremfall Root-FS voll → Totalausfall.
**Empfohlene nächste Schritte:** GC-Strategie an tatsächliche Rebuild-Frequenz anpassen (z. B. `nix.gc.dates` täglich statt wöchentlich, `--delete-older-than` deutlich verkürzen, oder Generationen explizit auf eine kleine Anzahl begrenzen statt nur Boot-Menu-Einträge via `configurationLimit`); alternativ Rebuild-Frequenz der Automatisierung selbst hinterfragen (muss jeder einzelne Board-Job sofort `switch` auslösen?).
**Konfidenz:** Hoch (direkt aus `df`, `journalctl`, Generationenliste und Rebuild-Zähler belegt).
### F2 — pinix seit ~1 Tag über Tailscale nicht erreichbar, mehrere Public-Routes tot (Critical)
**Komponenten:** pinix (Tailnet-Konnektivität), Traefik-Routing (`routes-external.nix`), Forgejo-Webhooks, Kanboard/„board", GoToSocial/„social", „phanpy", „sound", Radicale/„calendar"
**Beobachtung:** `tailscale status` zeigt pinix als „offline, last seen 1d ago" (tx>0/rx=0 — einseitig tot). Live-Checks gegen alle Traefik-Routen, die auf `tailnetIPs.pinix` zeigen, laufen in einen TLS-Handshake-Erfolg gefolgt von vollständigem Timeout; rein lokale Routen (`data`, `hdm`, `head`, alle `127.0.0.1`) liefern HTTP 200.
**Evidenz:**
```
100.64.0.3 pinix worker@ linux active; relay "fra"; offline, last seen 1d ago, tx 6240 rx 0
board.0ff.space -> Operation timed out after 15002 milliseconds
social/phanpy/sound/calendar.0ff.space -> http_code 000 (Timeout)
data/hdm/head.0ff.space -> http_code 200
Sep 11 16:33:16 blunix forgejo[...]: Unable to deliver webhook task[1374] ... http://100.64.0.3:9000/hooks/wiki-update ... context deadline exceeded
```
**Erwarteter Zustand:** pinix als Tailnet-Peer aktiv, alle darüber gerouteten Public-Services erreichbar.
**Tatsächlicher Zustand:** pinix vom Tailnet aus nicht erreichbar; dadurch mindestens 5 nach außen beworbene Dienste (Board/Kanboard, Mastodon-Frontend, Phanpy, Sound, Calendar) faktisch down, plus tägliche Webhook-Fehlversuche gegen pinix.
**Vermutete Ursache:** Entweder pinix selbst ist down/hängt, oder ein Tailscale-/Netzwerkproblem auf pinix-Seite (z. B. IP-Wechsel, Stromausfall, Kernel-Update-Hänger). Ohne Zugriff auf pinix nicht abschließend klärbar.
**Mögliche Auswirkungen:** Nutzer-sichtbarer Totalausfall mehrerer Dienste seit ~24h, ohne dass dies (soweit im Audit sichtbar) bereits gemeldet/alarmiert wurde — deutet auf eine **Observability-Lücke** hin (kein Alerting für Tailnet-Peer-Verfügbarkeit oder Backend-Health der Traefik-Routen).
**Empfohlene nächste Schritte:** Sofortige manuelle Prüfung von pinix (Konsolen-/Out-of-Band-Zugriff, da SSH über Tailnet ja gerade das Problem sein könnte); danach Monitoring/Alerting für Tailnet-Peer-Status und Traefik-Backend-Health ergänzen.
**Konfidenz:** Hoch für „pinix nicht erreichbar" und „dadurch Route-Timeouts" (direkt gemessen); die eigentliche Ursache auf pinix selbst ist unbelegte Vermutung.
### F3 — Codeberg-Push-Mirror scheitert zyklisch seit Tagen (Medium)
**Komponenten:** Forgejo Push-Mirror (`lukas/nixos-config` → `codeberg.org/pijukka/nixos-config`)
**Beobachtung:** Wiederkehrender Fehler alle paar Stunden über mehrere Tage hinweg.
**Evidenz:**
```
Sep 11 13:54:49 blunix forgejo[608639]: Error pushing .../lukas/nixos-config.git mirror[2] ...: PushRejected
Sep 11 13:54:49 blunix forgejo[608639]: remote: Forgejo: branch master is the default branch and cannot be deleted
```
Lokal existiert kein `master`-Branch mehr (`git branch -a` zeigt nur `dev`/`production`), `origin/HEAD` zeigt aber noch auf `refs/remotes/origin/master`.
**Erwarteter Zustand:** Push-Mirror synchronisiert erfolgreich, kein wiederkehrender Fehler im Journal.
**Tatsächlicher Zustand:** Jeder Sync-Versuch versucht, den auf Codeberg als Default gesetzten `master`-Branch zu löschen, was Codeberg ablehnt — seit Tagen ununterbrochen wiederholt.
**Vermutete Ursache:** `master` wurde im Quell-Repo entfernt/umbenannt (vermutlich im Zuge der `dev`/`production`-Umstellung), ohne den Default-Branch auf dem Mirror-Ziel entsprechend nachzuziehen.
**Mögliche Auswirkungen:** Kein Datenverlust, aber dauerhaftes Fehlerrauschen im Journal, unnötige Last, und ein nicht mehr aktueller Codeberg-Mirror (bleibt vermutlich auf dem Stand vor der Branch-Umstellung).
**Empfohlene nächste Schritte:** Default-Branch auf Codeberg-Seite auf `production` oder `dev` umstellen (oder Mirror-Konfiguration entsprechend anpassen), danach Journal auf Wiederholung prüfen.
**Konfidenz:** Hoch (Fehlermeldung ist eindeutig, lokale Branch-Situation bestätigt die Diskrepanz).
### F4 — Verwaistes GoToSocial-Datenverzeichnis auf blunix (Low, Cleanup)
**Komponenten:** `/var/lib/gotosocial` auf blunix, GoToSocial-Service (laut Repo nur auf pinix definiert)
**Beobachtung:** `du -sh /var/lib/gotosocial` liefert 117M auf blunix, obwohl `hosts/pinix/localServices/gotosocial.nix` der einzige Ort im Repo ist, der den Service definiert; `systemctl status gotosocial` auf blunix meldet „could not be found".
**Erwarteter Zustand:** Keine GoToSocial-Daten auf einem Host, der den Service gar nicht betreibt.
**Tatsächlicher Zustand:** 117 MB toter Daten-Altlast auf einer Platte, die gerade bei 96 % liegt (F1).
**Vermutete Ursache:** Migration von GoToSocial von blunix nach pinix, Altdaten wurden nicht bereinigt.
**Mögliche Auswirkungen:** Unnötiger Verbrauch von knappem Speicherplatz; potenzielle Verwechslungsgefahr bei zukünftigen Debugging-Sessions.
**Empfohlene nächste Schritte:** Verifizieren, dass die Daten wirklich nicht mehr gebraucht werden (z. B. Vergleich mit dem aktiven Datenstand auf pinix, sobald erreichbar), dann manuell entfernen.
**Konfidenz:** Mittel — Verzeichnisinhalt selbst war wegen fehlender Leserechte nicht einsehbar, nur die Größe und der Servicename sind belegt.
### F5 — LLDAP-Admin-UI öffentlich ohne zusätzliche Auth-Schicht exponiert (Medium, Security)
**Komponenten:** `hosts/blunix/localServices/lldap.nix`, `hosts/blunix/localServices/traefik/routes-external.nix` (Route „lldap")
**Beobachtung:** `https://lldap.0ff.space/` liefert HTTP 200 (Login-Seite) ohne Traefik-`basicAuth`-Middleware, im Unterschied zur Traefik-API-Route, die per `middlewares = ["auth"]` geschützt ist (HTTP 401 bestätigt).
**Erwarteter Zustand / Vergleich:** Andere sensible interne Tools (`intent-board`) sind bewusst mit `middlewares = ["auth"]` versehen; LLDAP als zentraler Identitäts-/Admin-Dienst hat dieses zusätzliche Netzwerk-Gate nicht.
**Vermutete Ursache:** LLDAP verlässt sich allein auf sein eigenes Login (Passwort-Auth), vergleichbar mit der bewussten Design-Entscheidung bei „calendar" (Kommentar: „Radicale's own per-request LDAP auth is the real security boundary"). Bei LLDAP ist das aber der Verzeichnisdienst selbst, dessen Kompromittierung (z. B. Brute-Force, ungepatchte CVE) alle nachgelagerten Auth-Flows (Dex, oauth2-proxy) betrifft.
**Mögliche Auswirkungen:** Größere Angriffsfläche für den zentralen Identity-Provider als nötig; kein Brute-Force-Schutz auf HTTP-Ebene sichtbar (nur generisches fail2ban, Jail-Details nicht einsehbar).
**Empfohlene nächste Schritte:** Prüfen, ob `basicAuth`- oder IP-/Tailnet-Beschränkung für die LLDAP-Web-UI sinnvoll ergänzt werden kann, ohne den beabsichtigten Nicht-Tailnet-Zugriff (falls gewollt) zu brechen; alternativ gezielte fail2ban-Jail für LLDAP-Login-Fehlversuche verifizieren/ergänzen.
**Konfidenz:** Mittel — die Exposition ist belegt, ob das eine bewusste Design-Entscheidung war (wie bei „calendar" dokumentiert) oder ein Versehen, ist aus dem Repo nicht eindeutig ersichtlich (kein entsprechender Kommentar wie bei anderen Routen).
### F6 — Wiederkehrende Forgejo „bad object"-Fehler bei PR-Diff-Stats (Low)
**Komponenten:** Forgejo, `GetPullDiffStats`
**Beobachtung:** Drei distincte Objekt-Hashes (`059210b7…`, `13f74c33…`, `45db7d4d…`) tauchen über mehrere Tage hinweg wiederholt als „fatal: bad object" auf.
**Erwarteter Zustand:** Diff-Stats-Berechnung für alle offenen PRs funktioniert fehlerfrei.
**Tatsächlicher Zustand:** Für (vermutlich) einzelne PRs mit inzwischen nicht mehr existenten Commits (z. B. nach Force-Push/Rebase eines Fork-Branches) schlägt die Berechnung dauerhaft fehl und wird periodisch erneut versucht.
**Vermutete Ursache:** Stale PR-Referenz auf gelöschten/umgeschriebenen Branch-Kopf, kein Repo-Korruptionsproblem des Hauptrepos.
**Mögliche Auswirkungen:** Kosmetisch (fehlende Diff-Stats-Anzeige für betroffene PR(s)), plus unnötige wiederkehrende Last/Log-Rauschen.
**Empfohlene nächste Schritte:** Betroffene(n) PR(s) identifizieren (über Forgejo-UI/DB) und schließen oder neu synchronisieren.
**Konfidenz:** Mittel (Fehlermuster eindeutig, genaue betroffene PR nicht identifiziert).
### F7 — MySQL/MariaDB lauscht auf `0.0.0.0:3306` statt `127.0.0.1` (Informational)
**Komponenten:** MySQL/MariaDB (WordPress-Backend), Firewall
**Beobachtung:** `ss -tlnp` zeigt `0.0.0.0:3306` und `[::]:3306`; die Firewall-Konfiguration (`allowedTCPPorts = [22 80 443 5222 5269]`, keine `trustedInterfaces`, kein `tailscale0`-Sonderfall für 3306) lässt aber keinen externen oder Tailnet-Zugriff zu.
**Erwarteter/tatsächlicher Zustand:** Kein akutes Risiko, da die OS-Firewall den Port blockt; sauberer wäre dennoch ein `bind-address = 127.0.0.1`, um Defense-in-Depth nicht allein von der Firewall-Regel abhängig zu machen.
**Mögliche Auswirkungen:** Gering, solange Firewall-Konfiguration unverändert bleibt; Risiko steigt bei künftigen Firewall-Änderungen (z. B. neuer `trustedInterfaces`-Eintrag).
**Empfohlene nächste Schritte:** `bind-address`/`http_host`-Äquivalent für MySQL auf `127.0.0.1` setzen, falls kein externer DB-Zugriff je benötigt wird.
**Konfidenz:** Hoch für die Beobachtung, mittel für die Risikoeinschätzung (abhängig von künftigen Konfigurationsänderungen).
## Positive Findings
- **Backups laufen zuverlässig:** `restic-backups-vpsBackup` hat an allen drei geprüften Tagen (09.–11.09.) erfolgreich Snapshots erzeugt, auch am Tag des Disk-Vorfalls — die Backup-Kette selbst war nicht betroffen.
- **Selbstheilung des Forgejo-Dumps:** Nach dem akuten Space-Vorfall am 10.09. lief der Forgejo-Dump am 11.09. wieder sauber durch (`Finished dumping in file forgejo-dump-…`), sobald wieder Platz frei war — kein manuelles Eingreifen nötig.
- **Durchdachte, dokumentierte GC-Tuning-Historie:** `hosts/nix-gc.nix` zeigt bereits eine bewusste, aus einem Preflight abgeleitete Anpassung (`docs/intent/nix-gc-plattform.md`, 2026-09-05) mit klar begründeten Host-spezifischen Schwellenwerten — das Problem in F1 ist also bereits erkannt und teilweise adressiert worden, reicht aber (siehe F1) angesichts der Rebuild-Frequenz nicht aus.
- **Saubere Trennung von Auth-Boundaries dort, wo dokumentiert:** Die `calendar`-Route hat eine explizit begründete Design-Entscheidung („Radicale's own per-request LDAP auth is the real security boundary"), die `intent-board`-Route bekam bewusst `basicAuth` ergänzt, nachdem ein Review das als Lücke markiert hatte — die Codebase zeigt an mehreren Stellen nachvollziehbare, kommentierte Sicherheitsentscheidungen statt Zufall.
- **Firewall-Policy minimal und explizit:** Nur 5 TCP-Ports global offen, alle weiteren Dienste laufen entweder rein lokal oder über gezielte `tailscale0`-Ausnahmen — kein Anzeichen einer „alles offen"-Konfiguration.
- **Keine failed systemd-Units zum Prüfzeitpunkt**, kein Service mit auffälliger Restart-Historie außer dem hier selbst laufenden Board-Worker-Job.
## Cross-System Observations
- **F1 (Disk voll) und die 34 Generationen/208 Rebuilds sind direkt kausal verknüpft:** Die hohe Automatisierungs-Kadenz der Board-/Builder-Pipeline (jeder abgeschlossene Job löst offenbar einen `nixos-rebuild switch` aus) unterläuft die am 2026-09-05 bewusst eingeführte GC-Politik. Das ist kein Konfigurationsfehler in `nix-gc.nix` selbst, sondern ein Mismatch zwischen einer für gelegentliche Rebuilds ausgelegten Politik und einer inzwischen viel höherfrequenten Realität.
- **F2 ist die gemeinsame Ursache für mindestens 5 scheinbar unabhängige Symptome:** Timeout auf `board.0ff.space`, `social.0ff.space`, `phanpy.0ff.space`, `sound.0ff.space`, `calendar.0ff.space` sowie die tagelang wiederkehrenden Forgejo-Webhook-Fehler gegen `100.64.0.3:9000` — alle laufen über denselben Tailnet-Pfad zu pinix. Ohne Korrelation hätte man das leicht als 6 getrennte Bugs behandelt.
- **Dokumentation vs. Runtime:** `docs/intent/nix-gc-plattform.md` beschreibt einen Zustand („blunix hat kaum Reserve, 29G Store auf 37G-Platte"), der sich seit dem 2026-09-05 durch die gestiegene Rebuild-Frequenz weiter verschärft hat (Store jetzt 25G, Gesamtbelegung 34G/37G) — die Doku ist also nicht falsch, aber die zugrunde liegende Annahme (Rebuild-Häufigkeit) hat sich seither verändert, ohne dass die Gegenmaßnahme nachgezogen wurde.
- **Kein sichtbares Alerting für beide Critical-Findings:** Weder der Disk-Vorfall vom 10.09. noch der seit ~24h laufende pinix-Ausfall scheinen ein aktives Monitoring/Alerting ausgelöst zu haben (soweit aus Journal/Config ersichtlich) — beides wäre ohne diesen Audit vermutlich erst durch Nutzerbeschwerden aufgefallen.
## Empfohlene Folge-Intents (priorisiert)
1. **[Reliability/Bugfix] GC-Policy an tatsächliche Rebuild-Frequenz von blunix anpassen.** Ziel: `nix.gc` täglich statt wöchentlich, kürzere Retention und/oder Begrenzung der Anzahl gehaltener System-Generationen, damit die min-free/max-free-Schwellen nicht durch Dutzende frischer Generationen unterlaufen werden. Bezug: F1, `hosts/nix-gc.nix`.
2. **[Reliability] pinix-Erreichbarkeit klären und wiederherstellen.** Ziel: Root Cause des Tailnet-Ausfalls seit ca. 24h ermitteln (Host down? Tailscale-Client hängt? Netzwerkproblem?) und Board/Social/Phanpy/Sound/Calendar wieder erreichbar machen. Bezug: F2. Höchste Nutzerrelevanz.
3. **[Observability] Alerting für Tailnet-Peer-Status und Disk-Füllstand ergänzen.** Ziel: Beide Critical-Vorfälle (F1, F2) hätten proaktiv erkannt werden können; ein einfacher Schwellenwert-Check (Diskbelegung, `tailscale status` Peer-Offline-Dauer) mit Benachrichtigung wäre risikoarm und hochwirksam.
4. **[Bugfix] Codeberg-Push-Mirror-Konfiguration an aktuellen Default-Branch (`production`/`dev`) anpassen.** Bezug: F3. Geringer Aufwand, beseitigt tagelanges Fehlerrauschen.
5. **[Cleanup] Verwaiste GoToSocial-Altdaten auf blunix identifizieren und entfernen**, nachdem pinix wieder erreichbar ist und der aktive Datenstand verifiziert werden kann. Bezug: F4.
6. **[Security] LLDAP-Web-UI-Exposition bewerten und ggf. zusätzliche Schutzschicht (Middleware/IP-Beschränkung/Rate-Limiting) ergänzen.** Bezug: F5.
7. **[Cleanup] Betroffene PR(s) mit „bad object"-Referenzen in Forgejo identifizieren und bereinigen.** Bezug: F6.
8. **[Security/Cleanup] MySQL `bind-address` auf `127.0.0.1` setzen als Defense-in-Depth**, unabhängig von der Firewall-Regel. Bezug: F7.
9. **[Architecture]** Grundsätzliche Diskussion, ob jeder einzelne Board-/Builder-Job wirklich einen sofortigen `nixos-rebuild switch` auslösen muss, oder ob Batching/Throttling der Deploys (z. B. max. 1 Switch pro X Minuten) die Systembelastung strukturell reduzieren würde — würde F1 nicht nur symptomatisch (GC), sondern ursächlich adressieren.
## Unsicherheiten / offene Punkte
- Die tatsächliche Ursache der pinix-Nichterreichbarkeit (F2) ist von blunix aus nicht abschließend diagnostizierbar (Host down vs. reines Netzwerkproblem).
- Ob die fehlende Middleware bei LLDAP (F5) eine bewusste Entscheidung oder ein Versehen war, ist aus dem Repo nicht mit Sicherheit ablesbar.
- Genaue Größe/Inhalt von `/var/lib/forgejo`, `/var/lib/mysql/*`, `/var/lib/traefik`, `/var/lib/postgresql` etc. blieb wegen fehlender Leserechte im Runtime-Pfad dieser Rolle unzugänglich; die Diskbilanz aus F1 könnte daher noch weitere, hier nicht sichtbare Verbraucher enthalten.
- Fail2ban-Jail-Konfiguration/-Wirksamkeit im Detail nicht prüfbar (`fail2ban-client` nicht im PATH der Sandbox).
## Fazit
Die Plattform ist grundsätzlich solide und mit erkennbarer Sorgfalt gepflegt (dokumentierte Design-Entscheidungen, funktionierende Backups, minimale Firewall-Policy). Der Audit deckt jedoch zwei bereits real eingetretene bzw. laufende Incidents auf, die ohne diesen Blick von außen leicht als mehrere unabhängige Kleinprobleme behandelt worden wären: ein selbstverschärfender Diskplatz-Engpass durch die hohe Automatisierungs-Kadenz der Deploy-Pipeline (F1), und ein seit rund einem Tag bestehender Totalausfall mehrerer öffentlicher Dienste durch einen nicht erreichbaren pinix-Host (F2). Beide sollten vorrangig behandelt werden; die übrigen Findings sind überwiegend kostengünstig zu beheben und primär Hygiene-/Cleanup-Charakter.