# Gotchas — ausführliche Diagnose-Anleitungen (Detail-Doku) Diese Datei trägt die ausführlichen Diagnose-Blöcke, die in `CLAUDE.md` nur noch als 1-Zeilen-Merkregel mit Zeiger stehen. Volltext hier, damit der Kern-Index schlank bleibt. Alle Blöcke sind **aktiv** (querschnittliche Fallen), keine Historie. --- ## SSDP-Relay für die macOS-Sonos-App LXC **108 `mcast-relay`** auf pve, zweibeinig `10.40.10.21` (VLAN10) + `10.40.40.21` (VLAN40), `multicast-relay` mit **`--noMDNS`** (mDNS macht der Core). Unit im Repo: **`mcast-relay/multicast-relay.service`**. **Zwei Beine sind zwingend** — SSDP ist link-lokal mit TTL 1, ein Relay muss Mitglied beider Broadcast-Domänen sein; Routing hilft nicht. - 🔴 **`--ssdpUnicastAddr` gehört in ein zweibeiniges Relay NICHT — die Flagge hat den Hinweg 7 Wochen lang blockiert** (drin 2026-08-18, ausgebaut **2026-08-25**). Sie schreibt in `multicast-relay.py` **Z. 630** die Quelle *jedes* SSDP-Pakets an `239.255.255.250:1900` auf `:1901` um (**auch NOTIFY**); beim Senden greift dann **Z. 691** `if srcAddr == ssdpUnicastAddr and not onNetwork(srcAddr, tx['addr'], tx['netmask']): continue` — `10.40.10.21` liegt nicht im VLAN40-Netz, also **verwarf der Relay die M-SEARCH selbst, bevor sie die Player erreichte**. Der Rückweg gehört stattdessen **geroutet**: `forward TP5: MEDIA->MAIN` ist offen, die Player antworten unicast an den echten Sucher. (Upstream nennt den Rückweg selbst `# FIXME: record more than one?` — es gibt nur **einen globalen** Merkslot.) - 🔎 **Symptom-Merkregel:** *App sucht hunderte Male, sieht NOTIFYs, baut aber nie eine Verbindung auf* = **Relay, nicht Netz**. Diagnose in einer Zeile — **Richtungsbilanz** im Journal: `grep -c "via eth1"` (VLAN10→VLAN40) gegen `grep -c "via eth0"`. **0 zu n heißt: der Hinweg fehlt.** - ⚠️ **Aus dem Relay heraus lässt sich der Relay nicht testen** (Loop-Schutz ignoriert eigene Quelladressen) — am echten Client testen oder `journalctl -u multicast-relay` mitlesen. **Und am Client nicht auf Port 1900 messen:** Sonos-App *und* Spotify halten dort je ein `SO_REUSEPORT`-Socket, die Unicast-Antwort bekommt nur **eines** davon. Richtig ist eine Probe mit **ephemerem Quellport** (`bind((ifaddr, 0))`), genau wie ein echter Client sucht. - 🔴 **Zweite, unabhängige Ursache desselben Falls (08-25): die Sonos-App suchte gar nicht.** Nach der Relay-Reparatur lag weiter nichts an — der Mitschnitt auf der VLAN40-Leitung (`pct exec 108 -- tcpdump -i eth1 -n -s0 -A "udp and host "`) zeigte: **jedes** SSDP-Paket des MacBooks kam von **Chrome** (`ST: urn:dial-multiscreen-org:…dial:1`, `USER-AGENT: Chromium`), **kein einziges** von Sonos. Die App hatte Sockets offen (`*:1900`, `*:6969`, `TCP *:3400`) und redete mit der Cloud, legte aber nichts auf die Leitung. Ursache war das **Local-Network-Gate von macOS**: es stand auf **„an" und griff trotzdem nicht**. Fix = Schalter unter *Datenschutz & Sicherheit → Lokales Netzwerk* **aus, App beenden, wieder an, App starten** (hart: `sudo tccutil reset LocalNetwork com.sonos.macController2`). ⇒ **Merkregel: „die App sucht hunderte Male" ist erst dann ein Befund, wenn der Mitschnitt sagt, WER sucht.** Im Handoff vom Vormittag waren die gezählten 291 Suchen Chrome + eigene Proben; die Zahl hat drei Stunden in die falsche Richtung gezeigt. - 🖥️ **Das MacBook ist dual-homed in VLAN10:** `en5` = **10.40.10.183** (USB-Dock, Default-Route) und `en0` = **10.40.10.82** (WLAN). Die früher als „zweiter Mac" gelesene `.183` ist **dasselbe Gerät** — beim Messen immer beide Beine prüfen. --- ## Konstanter 10-Sekunden-Hänger = DNS-Timeout, kein Lastproblem (Fund 2026-09-01, TP16.3-Randbefund.) `gitea` hing bei ~10 % der Anfragen exakt 10,1 s — quer über Web-UI, `/api/healthz` **und** den Git-Pfad, also kein Rendering. Ursache: **MariaDB (LXC 302) hatte `skip-name-resolve` auskommentiert** und machte bei **jeder neuen Verbindung** einen Reverse-Lookup, während ihr `/etc/resolv.conf` noch auf den toten `10.40.41.254` zeigte (glibc: 5 s × 2 Versuche = 10 s). Pool-Verbindungen waren schnell ⇒ es wirkte sporadisch. 🔑 **Drei Merkregeln daraus:** - (a) **immer gegen eine zweite Sache messen, die denselben Weg nimmt** — `vw`/`hass` über dieselbe Strecke hatten 0 von 30 Hängern, das hat CF, Tunnel, Firewall und Caddy in einem Schritt entlastet. - (b) **wer an einer DB hängt, sagt die Verbindungstabelle** (`ss -tn | grep 3306`), nicht die Vermutung — hier hingen **Vaultwarden, Home Assistant und gitea** an derselben MariaDB, und die Annahme „Vaultwarden nutzt SQLite" war schlicht falsch. - (c) **ein toter Resolver ist selten allein** — der Sweep über alle LXCs fand **fünf** Container mit `10.40.41.254`. Sweep: `for c in $(pct list|awk 'NR>1{print $1}'); do pct exec $c -- grep ^nameserver /etc/resolv.conf; done` --- ## networking.service failed bei funktionierendem Netz = tote `auto`-Stanzas (Ursache gefunden + behoben 2026-09-01.) In vier LXCs standen in `/etc/network/interfaces` noch Einträge aus dem **alten VLAN1-Schema** (`eth0` → `10.40.41.x`) und aus früheren Versuchen (`veth16`, `veth24`, Tippfehler `eth01`) — auf Interfaces, die es im Container gar nicht gibt. `ifup -a` scheitert daran, das echte `veth20` kommt trotzdem hoch. **Fix:** nur die Stanzas entfernen, deren Interface in `ip -br link` fehlt (`lo` und die echten behalten), Backup daneben. 🔴 **Abnahme ist ein echter Reboot, nicht `systemctl is-active`** — der Servicestatus sagt nichts darüber, ob beim nächsten Start etwas hochkommt. --- ## networking.service failed im LXC, ohne dass das Netz fehlt `networking.service` kann in einem LXC dauerhaft `failed` sein, ohne dass das Netz fehlt — und dann startet alles mit `After=network-online.target` nach einem Reboot **nicht** (Fund 2026-09-01: `101`, `102`, `106`, `107`; **influxdb2 kam nach dem Neustart nicht hoch**, Unit `enabled`, **kein Startversuch im Journal**). Fällt nur auf, wenn man neu startet — die Container liefen 13+ Tage. **Vor jedem geplanten LXC-Neustart `systemctl --failed` lesen und danach die Ports gegen vorher vergleichen**, sonst verliert man still einen Dienst. --- ## Messwerkzeug, das die falsche Frage beantwortet (zweimal in einer Nacht, 2026-09-01.) - (a) **`nc -z` lieferte falsch-negative** „Port zu" für neun Dienste gleichzeitig — inklusive des SSH-Ports, über den die Session gerade arbeitete; `curl` bekam von demselben Host **HTTP 200 in 24 ms**. **Bei „alles gleichzeitig kaputt" zuerst das eigene Werkzeug verdächtigen**, dann das Netz: ein Python-Socket oder `curl` entscheidet in Sekunden. - (b) **Ein Firewall-Zähler taugt nicht als Wegbeweis**, wenn der Client die Verbindung offenhält (`cloudflared`): er zählt nur NEUE Verbindungen und steht still, obwohl alles läuft — richtig ist die **Verbindungstabelle** (`/ip firewall connection`). --- ## VLAN20-Docker-Hosts: Host-DNS nach dem Umzug prüfen (2026-07-10, TP14.2a) NAS + pve-LXC zeigten `/etc/resolv.conf` noch auf totes `.41.254` → `docker pull` ghcr scheitert (`EAI_AGAIN`, aber Egress ok!). Fix = `.20.1`: LXC `pct set 400 --nameserver 10.40.20.1`; **Synology-Falle: DSM-„Allgemein"-DNS ≠ was `dockerd` liest** — Interface zieht DNS per DHCP → Fix an der *Netzwerkschnittstelle* „DNS manuell". Laufende Container frieren den `127.0.0.11`-Upstream zum Erstellzeitpunkt ein (Recreate nötig). Merkregel: `docker-pull-hängt` + `dns.lookup EAI_AGAIN` aber `TCP zu ghcr-IP:443 ok` = toter Resolver, nicht Egress. --- ## Zeitquelle ist der Core (NTP) `/system ntp server`, seit 2026-08-18, ausgeliefert per **DHCP-Option 42** (`ntp-server=` in jedem der 7 Netze) und drift-überwacht (ComplianceRule `system-ntp`). Vorher lief **nirgends** eine Synchronisation: die anderen drei Geräte zeigten auf `10.40.99.1`, wo kein Server lief, und der Core selbst hatte gar keinen NTP-Client — ap2 war dadurch **17 Stunden** versetzt. 🔴 **Zwei Fallen dabei:** - (a) ein NTP-Server mit `use-local-clock=no` und unsynchronisiertem Client liefert **Stratum 16**, das jeder Client verwirft — Server einschalten allein reicht nicht. - (b) wird der Server eingeschaltet, *bevor* sein Client synchron ist, hält er diesen Zustand fest → **`enabled=no`/`=yes` nach der Synchronisation**. Merkregel: bei widersprüchlichen Zeitstempeln zwischen Geräten zuerst `/system ntp client get status` lesen, und zum Eingrenzen einen Client testweise auf eine öffentliche Quelle zeigen lassen. --- ## Home Assistant: der `http:`-Block in `configuration.yaml` ist WIRKUNGSLOS (Fund 2026-08-26, TP31.) HA hat die http-Config nach **`.storage/http`** migriert (`"yaml_migration_done": true`); seither wird die YAML kommentarlos ignoriert — selbst ein ungueltiger Schluessel darin erzeugt **keinen** Config-Fehler. 🔴 **Die Logzeile fuehrt aktiv in die Irre:** `Received X-Forwarded-For header from an untrusted proxy ` faellt laut Quelltext nur bei **aktivem** `use_x_forwarded_for` — man haelt die Option fuer wirksam und die Liste fuer falsch und editiert die falsche Datei. Richtig ist der WS-Zweischritt **`http/config/configure`** (setzt `pending`, startet HA neu) → binnen **5 Minuten** **`http/config/promote`**, sonst Auto-Revert auf `stable`. Merkregel zur Eingrenzung: ein Testskript in `/python_scripts/` + `python_script.reload` — taucht der Service auf, liest HA das Verzeichnis, und die Frage ist nicht mehr *welche Datei*, sondern *warum ein gelesener Block nicht wirkt*. --- ## Nautobot auf der DS923 braucht einen abgeschalteten Image-Healthcheck Der eingebackene Check ruft alle 10 s `nautobot-server health_check` = einen vollen Django-Start; unter Last dauert der >2 min, die Aufrufe **stapeln sich unbegrenzt** → Speicher alle → `fork()` mit ENOMEM → DSM räumt den ganzen Stack ab (am 2026-08-17 zweimal passiert, Load bis 73 bei 4 Kernen). Im Stack stehen deshalb `healthcheck: disable: true` auf worker+scheduler, `--concurrency=2` und `mem_limit`. **`cpus:` geht auf Synology nicht** (Kernel ohne CFS-Quota, der Stack-Deploy schlägt sonst fehl).