hermes-erkenntnisse/netzwerk/2026-07-20-VM302-Netzwerk-Analyse.md

9.5 KiB
Raw Permalink Blame History

VM302 Netzwerk-Analyse & Optimierung — 2026-07-20

Vollständige Untersuchung der Latenz Deutschland ↔ Kansas City (VM302, A40-Workstation) sowie zweier kritischer Sicherheits-/Performance-Befunde.

TL;DR

  • Routing über Relays bringt NICHTS — der direkte Pfad ist bereits physikalisch optimal (3 Beweise)
  • Der echte Gewinn lag auf der Maschine: RSC abschalten = 7 ms, mehr als jedes Gateway geboten hätte
  • VM302 stand ungeschützt im Internet (ComfyUI/Ollama ohne Auth) — geschlossen
  • Tailscale lief über Relay statt direkt — Port-Forward-Fix: 162 → 127 ms, Jitter 40 → 0,8 ms

1. Sicherheitslücke (kritisch)

Befund: VM302s Windows-Firewall-Profil „Private" war deaktiviert, und die öffentliche NIC lag in genau diesem Profil. Folge: ComfyUI (:8188), Studio (:8502), Ollama (:11434), LiteLLM (:4000) waren unauthentifiziert aus dem Internet erreichbar. ComfyUI erlaubt Datei-Zugriff und via Custom-Nodes faktisch Code-Ausführung → A40 und System offen für jeden.

Fix — nur VM-Ebene filtern, Hosts offen lassen:

/etc/pve/firewall/cluster.fw     enable: 1, policy_in: ACCEPT   # Subsystem an, Default offen
/etc/pve/nodes/<node>/host.fw    enable: 1                       # erbt ACCEPT = ungefiltert
/etc/pve/firewall/302.fw         policy_in: DROP + Ausnahmen     # NUR hier wird gefiltert
qm set 302 --net1 ...,firewall=1                                 # nur die öffentliche NIC

Ausnahmen in 302.fw: 3389 (RDP), 47984-48010 (Moonlight), 41641 (Tailscale), ICMP. net0 (intern/NAT) bleibt ungefiltert = Rettungsleine, RDP über die NAT-IP bleibt immer erreichbar.

2. Tailscale: Relay statt Direktverbindung

Befund: tailscale status zeigte relay "ki1-us" — jede Verbindung lief über Virginia, also DE→USA→DE. Ursache: VM302 sitzt hinter NAT auf gpu1. Forwards für RDP und Moonlight existierten, für Tailscale UDP 41641 nicht.

Fix — BEIDE Regeln nötig:

# eingehend
iptables -t nat -A PREROUTING -i vmbr0 -p udp --dport 41641 -j DNAT --to-destination 10.10.10.102:41641
iptables -I FORWARD -p udp -d 10.10.10.102 --dport 41641 -j ACCEPT
# ausgehend: Quellport ERHALTEN
iptables -t nat -I POSTROUTING 1 -o vmbr0 -p udp -s 10.10.10.102 --sport 41641 \
  -j SNAT --to-source 173.208.162.26:41641
netfilter-persistent save

Nur DNAT reicht nicht — MASQUERADE würfelt sonst den Quellport, STUN meldet einen anderen Port als den geforwardeten, und das Mapping passt nicht zusammen. Ergebnis: 162 ms / 40 ms Jitter (Relay) → 127 ms / 0,8 ms Jitter (direkt).

3. RSC — der eigentliche Latenz-Fresser

Befund: nas2 → VM302 = 143,9 ms, nas2 → gpu1 = 134,8 ms. 9,1 ms Unterschied im selben Rechenzentrum. Ursache: Recv Segment Coalescing (RSC) auf den virtio-NICs aktiv — bündelt eingehende Pakete, spart CPU, kostet Latenz und Jitter.

Disable-NetAdapterRsc -Name "Ethernet 2"
Disable-NetAdapterRsc -Name "Ethernet"

Ergebnis: VM302 132,3 ms · Abstand zu blankem Blech 9,1 → 2,0 ms · netto ~7 ms Gewinn. RSS war bereits aktiv (16 Queues), Offloads korrekt.

4. Routing-Analyse — warum kein Relay hilft

Weg Ergebnis
Direkt DE → VM302 121 ms, ±2 ms Jitter, 0 % Verlust
über Netcup DE (gw) +15 ms
über Netcup Virginia +9 ms
alle VM302-Ziele über gw +15…20 ms

Traceroute: beide Wege über Arelion/Telia (62.115.x). Direkter Pfad ohne Umweg, Zielnetz ab Hop 13. Geografie: Virginia = Ostküste (94 ms), Kansas City = Landesinneres (121 ms) → über Virginia fährt man 27 ms extra.

Messfallen, die zu Fehlschlüssen führen:

  • TCP-Handshake über einen nginx-Stream-Proxy misst nichts — nginx nimmt lokal an, bevor es das Backend kontaktiert (zeigte 3,5 ms statt der echten Strecke). Stattdessen echten Protokoll-Roundtrip messen (RDP X.224 CR→Confirm).
  • Ping-Summen unterschätzen Relays systematisch — Annahme/Pufferung/Neuversand tauchen darin nicht auf. Gemessene Realität bei gw: +15 ms, obwohl die Summe „gleichauf" vorhersagte.
  • tailscale netcheck nutzt einen eigenen Socket — der dort gemeldete Port ist NICHT tailscaleds 41641.

Fazit: 7.000 km über ein Tier-1-Backbone sind ~121 ms. Kein Relay, Tunnel oder Peering-Trick geht darunter. Echte Hebel: Protokoll (Moonlight statt RDP), Maschine (RSC), Architektur (Ergebnisse nach DE pushen statt mehrfach queren).

5. Zwei eigene Fehler — zur Warnung

a) Proxmox-Cluster-Falle. gpu1 und pm1 bilden consoro-cluster. /etc/pve/ ist geteiltes Cluster-Dateisystemcluster.fw mit enable: 1 auf gpu1 schaltete die Firewall auch auf pm1 ein → dort SSH tot, Web-UI-Timeouts bei VM-Details (PVEFW-HOST-IN lässt SSH nur aus IPSET management, und das war leer). ➡️ Vor jedem Proxmox-Firewall-Eingriff pvecm status prüfen.

b) policy_in ist keine gültige host.fw-Option (gehört in cluster.fw). Falsch gesetzt → Host-Policy fiel auf DROP zurück → Selbst-Aussperrung per SSH. Gerettet hat Tailscale, weil ts-input vor der PVE-Kette akzeptiert. ➡️ Bei Firewall-Arbeiten immer einen zweiten, ungefilterten Zugangsweg offen halten.

c) Unbelegte Behauptung. Ich hatte gewarnt, der DERP auf dem Mailserver störe die Mailzustellung — ohne zu messen. Nachgemessen: 0,1 % CPU, 2 Verbindungen, 1 Logzeile/Stunde. Die Behauptung war falsch. ➡️ Erst messen, dann warnen.

6. Latenz-Matrix (Referenz)

Gemessen von nas2 (Standort Bär, ohne WARP-Verfälschung):

nas2 → ms Server → gpu1 ms
DERP-DE (Mailserver) 24,3 Mailserver 111,4 (bestes Peering)
DERP-US (Virginia) 106,6 Hub 120,5
gpu1 130135 nas2 134,8
VM302 (nach Tuning) 132,3

Wichtig: Bär nutzt Cloudflare WARP → Messungen an seinem Client sind verfälscht. Immer von nas2 oder gpu1 aus messen.


NACHTRAG — Thema abgeschlossen (Endstand 2026-07-20)

Weitere Messungen nach dem ersten Bericht

Cloudflare Tunnel — mein Messfehler und die Korrektur

Erster Test zeigte scheinbar 90 ms Gewinn durch einen Cloudflare Quick Tunnel. Das war falsch. Ursache: der Testserver war ein einthreadiger Python-BaseHTTPRequestHandler, der die Direktmessung ausbremste (274 ms bei 132 ms echter Netzlaufzeit).

Neumessung mit ThreadingHTTPServer + TCP_NODELAY + keep-alive, gleiches Backend für beide Wege:

Weg Median Dauerbetrieb
Direkt (http) 130144 ms ← entspricht exakt dem Ping
Cloudflare-Tunnel (https) 166227 ms

➡️ Cloudflare ist 3580 ms LANGSAMER. Kein Domain-Umzug nötig. ➡️ Lehre: bei Latenzmessungen immer prüfen, ob der Testserver selbst der Flaschenhals ist.

Warum Cloudflares 1-ms-Nähe nicht hilft

gpu1 → 1.1.1.1 = 1,06 ms, PoP-Kennung mci03 (= Kansas City), 6 Hops, echtes Cloudflare (kein Provider-Hijack). Aber: Diese 1 ms decken nur den ersten Meter. Der Atlantik bleibt. Ein Anycast-Ping misst, wo die nächste Edge steht — nicht, wie schnell das Backbone nach Europa trägt.

Alle Varianten im Endstand

Variante Ergebnis
Direkt 121 ms (RZ) · 130 ms (nas2) · 150 ms (Client)
Cloudflare-Tunnel +35…80 ms
Netcup-DE-Relay +15 ms
Netcup-Virginia +9 ms
NordVPN Meshnet ±0 (funktional = Tailscale)
Multi-Routing-Broker nicht bauen — Tailscale leistet das bereits
RSC-Tuning VM302 7 ms (einziger echter Gewinn)

Bärs Anschluss ist Starlink (SpaceX-IP, Berlin) → systembedingter Jitter, nicht wegoptimierbar. Sein Client misst 150 ms, sein NAS am selben Anschluss 130 ms → Verdacht WLAN/Client-seitig.

Weitere Sicherheitsbefunde (alle geschlossen)

Sunshine-Admin-Oberfläche stand offen

Port 47990 öffentlich erreichbar, ohne jede Zugangsdaten (credentials/ enthält nur TLS-Zertifikate, sunshine.conf hat kein username/password). Wer die URL aufrief, konnte sich als Admin einrichten, Geräte koppeln und den Desktop streamen. ➡️ 47990 aus der Proxmox-Regel entfernt und die DNAT-Weiterleitung auf gpu1 gelöscht.

DNAT verschleierte alle RDP-Absender

DNAT tcp dpt:3389 → 10.10.10.102   destination 0.0.0.0/0   ← griff auch für .43

Folge: jede RDP-Verbindung erschien als 10.10.10.1 — auch die Angriffe aus Ungarn (80.94.95.152) und Moskau (62.205.169.50). EvlWatcher war blind und hätte beim Sperren Bär selbst ausgesperrt. ➡️ DNAT auf -d 173.208.162.26 eingegrenzt. .43 läuft direkt mit echter Absender-IP, .26 bleibt als Rettungsleine.

Merksatz: DNAT-Regeln ohne Ziel-IP-Bindung hebeln VM-Firewalls aus, weil der Traffic am gefilterten Interface vorbei auf die interne Karte umgeleitet wird.

Moonlight/Sunshine — Ursache

sunshine_state.json: 0 gekoppelte Geräte. Ohne Kopplung kein Stream. Sunshine läuft als SYSTEM in Sitzung 1 (Konsole), virtueller Display-Adapter (SudoMaker) vorhanden, Aufnahme funktioniert (1600x1156 @ 66 Hz). Desktop-Duplication funktioniert in RDP-Sitzungen nicht — deshalb muss Sunshine auf der Konsole laufen. Kopplung: Client in Tailscale → Moonlight „+" → 100.104.5.57 → PIN unter https://100.104.5.57:47990.

Fazit

7.000 km über ein Tier-1-Backbone sind ~121 ms. Kein Relay, Tunnel, Mesh oder Broker geht darunter. Für 510 €/Monat existiert keine Lösung, die das ändert. Einziger echter Hebel: GPU-Maschine in Europa. Praktisch nutzbar: Protokollwahl (Moonlight statt RDP) und Ergebnisse nach DE pushen statt den Ozean mehrfach queren.