Was macht lan-direct?
Leiten Sie den Datenverkehr der App über den ISP, während Sie als Agent im VPN bleiben.
Funktioniert sowohl in Claude Code als auch in Codex – der Mechanismus ist die Pro-Socket-Bindung, die nichts mit der Nutzeroberfläche zu tun hat.
Die Invariante
Ändern Sie niemals die Routingtabelle, die WinINET/System-Proxy-Einstellungen oder die Konfiguration des VPN-Clients. Nur:
- Setzen Sie Umgebungsvariablen, die auf einen Kindprozess beschränkt sind, oder
- übergeben Sie Per-Tool-Quellbindungs-Flags.
Beides ist Pro-Socket und Opt-In, sodass Ihre eigene Verbindung nicht beeinträchtigt werden kann. Das ist der Sinn dieser Fertigkeit – wenn Sie zu route add greifen, haben Sie sie gebrochen (siehe Abschnitt Notluke am Ende).
Schlagen Sie nicht vor, die VPN zu trennen. Das ist das Problem, das diese Fertigkeit vermeidet.
Arbeitsablauf
1. Erkennen und überprüfen
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\lan-detect.ps1
Unter Linux oder macOS verwenden Sie stattdessen das Gegenstück – gleiches JSON, gleicher Exit-Code-Vertrag:
bash scripts/lan-detect.sh
Gibt JSON aus: lanIp, gateway, lanDns, subnet, tunnelActive, vpnAdapter, directEgress, lanEgress, fakeIpDns, bypassWorks. Beendet sich nur mit Exit-Code 0, wenn bypassWorks wahr ist – es beweist die Umgehung mit zwei Live-Probes, anstatt sie nur zu vermuten.
tunnelActive: false-> Kein VPN ist aktiv. Sagen Sie es und stoppen Sie; es gibt nichts zu umgehen.bypassWorks: falsebei aktivem Tunnel -> Gehen Sie zu Fehlerbehebung unten. Fahren Sie nicht fort. Der Datenverkehr würde stillschweigend im VPN bleiben und Sie würden einen falschen Erfolg melden.
2. Mechanismus auswählen
Node-Backend (inkl. Next.js)? Überspringen Sie den Proxy – springen Sie zum Node-Rezept unter Rezepte pro Stack. Eine Umgebungsvariable, kein Proxy-Prozess, und es ist die einzige Möglichkeit, die natives fetch erreicht.
Alles andere: Starten Sie den LAN-gebundenen Proxy. Ein Serverprozess hat kein --interface-Flag, daher ist dies der Weg, ihm einen ISP-Ausgang zu geben.
node scripts/lan-proxy.mjs --bind <lanIp> --port 8899 # im Hintergrund ausführen
node scripts/lan-proxy.mjs --bind <lanIp> --port 8899 --dns <lanDns> # wenn fakeIpDns: true
Es lauscht nur auf 127.0.0.1 und protokolliert jeden Host, den es tunnelt, sodass Sie sehen können, was die App tatsächlich aufgerufen hat.
3. Backend mit Proxy-Adresse neu starten
HTTP_PROXY=http://127.0.0.1:8899
HTTPS_PROXY=http://127.0.0.1:8899
NO_PROXY=localhost,127.0.0.1,<subnetz>
NO_PROXY ist wichtig: Ohne sie werden die Aufrufe des Backends an seine eigenen lokalen Dienste grundlos durch den Proxy geleitet. (Lokale DBs über TCP – MySQL, Postgres, Mongo – sind nicht HTTP und werden ohnehin nicht beeinflusst.)
Setzen Sie diese beim Startbefehl des Backends, nicht global. Siehe Rezepte pro Stack unten – HTTP_PROXY allein reicht für mehrere Stacks nicht aus.
4. Testen und bestätigen
Rufen Sie den Endpunkt auf, dessen ausgehender Aufruf fehlschlug. Bestätigen Sie beides:
- der Aufruf ist jetzt erfolgreich, und
- das Proxy-Protokoll zeigt den Host, den es angewählt hat.
Ein Erfolg ohne passende Protokollzeile bedeutet, dass die Anfrage nie durch den Proxy gegangen ist.
5. Abbau
Stoppen Sie den Proxy, starten Sie das Backend ohne die Umgebungsvariablen neu. Nichts weiter rückgängig zu machen – es wurde kein globaler Zustand geändert.
pkill -f lan-proxy aus Git Bash tötet nicht eine Windows-node.exe. Verwenden Sie:
Get-CimInstance Win32_Process -Filter "Name='node.exe'" |
Where-Object { $_.CommandLine -like '*lan-proxy*' } |
ForEach-Object { Stop-Process -Id $_.ProcessId -Force }
Eine übrig gebliebene Instanz ist harmlos, führt aber beim nächsten Start zu einem Portkonflikt.
Rezepte pro Stack
| Stack | Wie man den Proxy übergibt |
|---|---|
Python requests / httpx | Umgebungsvariablen, wie sie sind |
Go, .NET HttpClient | Umgebungsvariablen, wie sie sind |
| PHP CLI | libcurl liest http_proxy / https_proxy aus der Prozessumgebung |
| Node (inkl. Next.js) | Nicht der Proxy – verwenden Sie das lan-bind.mjs-Preload, siehe unten |
| PHP unter Apache/XAMPP | siehe unten – der Dienst erbt Ihre Shell nicht |
| curl, wget, npm, ssh, git | Überspringen Sie den Proxy, binden Sie direkt (siehe Direkte Bindung unten) |
Node – Preload verwenden, nicht den Proxy
Natives fetch läuft auf Node's eingebautem undici, das HTTP_PROXY unter Node <= 23 ignoriert und kein https.Agent akzeptiert. Bestätigt unter Node 22.20: einfache Umgebungsvariablen, NODE_USE_ENV_PROXY=1 und --use-env-proxy tun alle nichts – das Proxy-Protokoll bleibt leer und der Datenverkehr geht stillschweigend über das VPN. Dies betrifft Next.js, das openai-SDK und alles andere auf nativem fetch.
Überspringen Sie den Proxy vollständig und verwenden Sie das Preload, das jeden ausgehenden Socket im Prozess bindet:
LAN_BIND=<lanIp> node --import "file:///<skill-verzeichnis>/scripts/lan-bind.mjs" script.js
LAN_BIND=<lanIp> NODE_OPTIONS="--import file:///<skill-verzeichnis>/scripts/lan-bind.mjs" npm run dev
<skill-verzeichnis> ist das eigene Basisverzeichnis dieser Fertigkeit mit Vorwärtsschrägstrichen – normalerweise C:/Users/<ihr_name>/.claude/skills/lan-direct unter Claude Code, oder C:/Users/<ihr_name>/.agents/skills/lan-direct unter Codex. --import benötigt unter Windows eine absolute file://-URL; ein reiner Windows-Pfad mit Rückwärtsschrägstrichen schlägt fehl.
NODE_OPTIONS propagiert an geforkte Worker, daher deckt es Next.js- und Vite-Entwicklungsserver ab.
Dies erreicht natives fetch, das openai-SDK, axios, node-fetch, got und einfaches http/https auf einmal – keine Abhängigkeit, kein Proxy-Prozess, kein HTTP_PROXY nötig. Es überspringt Loopback-Ziele, sodass eine lokale DB oder ein Entwicklungsserver weiterhin funktioniert.
Nur falls das Preload nicht verfügbar ist: Node >= 24 beachtet NODE_USE_ENV_PROXY=1 mit den Umgebungsvariablen, und axios beachtet sie in jeder Version.
PHP unter Apache / XAMPP
SetEnv/PassEnv in httpd.conf füllt nur $_SERVER; libcurl liest die Prozessumgebung, daher wird es sie nicht aufnehmen. Verwenden Sie eine der folgenden Methoden:
- Starten Sie Apache aus einer Shell, die bereits
http_proxy/https_proxyexportiert hat (z.B.xampp\apache_start.bat), oder putenv('https_proxy=http://127.0.0.1:8899');vorcurl_init(), odercurl_setopt($ch, CURLOPT_PROXY, '127.0.0.1:8899');direkt.
file_get_contents() beachtet keine davon – es benötigt einen Stream-Kontext mit 'proxy' => 'tcp://127.0.0.1:8899'.
Direkte Bindung
Kein Proxy nötig, wenn das Tool seinen eigenen Socket binden kann:
| Tool | Flag |
|---|---|
| curl | --interface <lanIp> |
| wget | --bind-address=<lanIp> |
| npm | --local-address=<lanIp> |
| ssh | -b <lanIp> |
| Chromium / Playwright | kein Bind-Flag vorhanden – verwenden Sie den Browser-MCP auf Port 8900, siehe unten |
Browser / Playwright MCP
Chromium hat kein Quellbindungs-Flag, daher erreicht ein Browser den ISP nur über den Proxy. Verwenden Sie lan-browser.mjs: Es ist ein Playwright-MCP-Server, der seinen eigenen Proxy startet und besitzt, sodass der Browser nie ohne einen solchen starten kann.
Es wird mit dieser Fertigkeit ausgeliefert – scripts/install.ps1 registriert es:
powershell -NoProfile -ExecutionPolicy Bypass -File <skill-verzeichnis>\scripts\install.ps1
Welche Hosts den ISP verwenden, stammt aus drei zusammengeführten Quellen, sodass dies fast nie eine Neuinstallation erfordert: lan-hosts.txt im Fertigkeitsverzeichnis (ausgelieferte Standardwerte, bei git pull ersetzt), ~/.lan-direct-hosts (die eigenen des Benutzers, niemals überschrieben) und --lan-hosts a,b beim Start. Eine Regel pro Zeile, #-Kommentare erlaubt, Suffix-Übereinstimmung.
Wenn ein Benutzer wünscht, dass ein anderer Host über den ISP geroutet wird, fügen Sie eine Zeile zu ~/.lan-direct-hosts hinzu und sagen Sie ihm, er solle den Browser neu starten – bearbeiten Sie nicht lan-hosts.txt, das beim nächsten Update überschrieben wird.
Wenn der Benutzer fragt, es von Hand zu registrieren, beachten Sie, dass -- den Parameterbinder von PowerShell überleben muss – übergeben Sie die Argumente als Array oder führen Sie es von bash aus:
# aus einem Klon
claude mcp add playwright-split --scope user -- \
node <skill-verzeichnis>/scripts/lan-browser.mjs --lan-hosts ".ir"
# von npm – überlebt das Verschieben des Checkouts, daher vorziehen, wenn der Benutzer es installiert hat
claude mcp add playwright-split --scope user -- npx -y lan-direct browser
Andere CLI-Unterbefehle, wenn das Paket installiert ist: lan-direct detect wählt das richtige Erkennungsskript für die Plattform, und lan-direct route <host> beantwortet „würde dieser Host über den ISP oder den Tunnel gehen?", ohne einen Browser zu starten. Greifen Sie darauf zurück, wenn ein Benutzer meldet, dass eine Seite nicht lädt – eine falsche Regel und eine nicht erreichbare Seite sehen von außen identisch aus.
Der Server erkennt die LAN-IP, verweigert den Start, wenn lan-detect sagt, dass die Umgehung defekt ist, verwendet einen vorhandenen Proxy wieder, falls bereits einer lauscht, und fährt herunter, was er gestartet hat, wenn der MCP beendet wird. Seine eigenen Protokolle gehen nach stderr; stdout bleibt für JSON-RPC sauber.
Er verwendet Port 8900, bewusst nicht den Port 8899, der oben für Backend-Tests verwendet wurde. Die Wiederverwendung erfolgt allein nach Port, sodass das Teilen der Nummer dazu führen würde, dass ein Alles-bindendes Backend-Proxy den Browser stillschweigend einfängt und seinen gesamten Datenverkehr über den ISP leitet.
Gemischtes Browsen funktioniert in einem Browser. --lan-hosts lässt den Proxy pro Host entscheiden: übereinstimmende Hosts verlassen über den ISP, alles andere bleibt ungebunden und nimmt den Tunnel. „Überprüfe hoosha und youtube" erfordert also kein Tool-Wechsel – hoosha geht über den ISP, youtube über das VPN, dieselbe Sitzung. Das Proxy-Protokoll zeigt die Entscheidung in jeder Zeile:
CONNECT lan hoosha.com:443
CONNECT vpn youtube.com:443
Halten Sie die Liste genau: Ein fehlender lokaler Host erhält den Tunnel und schlägt mit einer leeren Antwort fehl, und ein fälschlicherweise hinzugefügter ausländischer Host erhält den ISP und wird möglicherweise gefiltert. Wenn eine Seite auf eine Weise ausfällt, die wie eine tote Verbindung aussieht, überprüfen Sie, welche Route das Protokoll gewählt hat, bevor Sie annehmen, dass die Seite down ist.
Warum eine explizite Liste und keine automatische Erkennung: Das Verbinden mit einem blockierten Host durch den Tunnel gelingt auf TCP-Ebene (gemessen: connect@14ms) und stirbt erst ~860ms später, nachdem der Proxy bereits mit 200 Connection Established geantwortet hat. Ein Fallback würde bedeuten, den TLS-Handshake zu puffern und wiederzugeben und diese Verzögerung bei jeder lokalen Anfrage zu bezahlen.
Playwright routet Loopback durch den Proxy. Chrome umgeht normalerweise localhost, aber Playwright überschreibt dies, wenn ein Proxy gesetzt ist, sodass http://127.0.0.1:3000 bei lan-proxy.mjs ankommt, anstatt direkt zu gehen. Bestätigt im Proxy-Protokoll. Die Loopback-Sperre des Proxys ist das, was lokale Entwicklungsserver erreichbar hält – ohne sie würde jede dieser Anfragen mit EADDRNOTAVAIL fehlschlagen. Fügen Sie kein --proxy-bypass=<-loopback> hinzu; es ändert hier nichts und verwirrt nur das Bild.
Fehlerbehebung
directEgress entspricht lanEgress bei aktivem Tunnel. Das VPN erzwingt eine Kill-Switch oder strikte Route (ein WFP-Filter, der gebundene Sockets blockiert). Beheben Sie es im VPN-Client, nicht drum herum: Deaktivieren Sie die strikte Route oder fügen Sie eine Direkt-/Bypass-Routingregel für die benötigten Hosts hinzu. nekoray/sing-box: Schalten Sie strict_route aus oder fügen Sie eine direct-Ausgangsregel hinzu.
Unter Linux kann dies auch ohne Kill-Switch passieren: Eine Quelladresse allein überschreibt dort nicht die Routingtabelle wie unter Windows, sodass Policy-Routing den Datenverkehr im Tunnel hält. Die Lösung ist eine Regel, die Datenverkehr von der LAN-IP über das physische Gateway sendet – ip rule add from <lanIp> table <n> plus eine Standardroute in dieser Tabelle. Dies erfordert Root und ist eine systemweite Änderung, erklären Sie es also und lassen Sie den Benutzer entscheiden. Alles andere in dieser Fertigkeit bleibt unprivilegiert und prozessbezogen.
fakeIpDns: true. Der OS-Resolver gibt 198.18.x.x-Platzhalter zurück, die nur innerhalb des Tunnels eine Bedeutung haben. Übergeben Sie --dns <lanDns> an den Proxy, damit er über das eigene DNS des LANs auflöst.
Ausgangsprobe gibt nichts zurück. Keine Konnektivität zum Probe-Host. Überprüfen Sie die Verbindung, führen Sie es erneut aus.
Notluke
Wenn ein Backend wirklich nicht proxyt werden kann (eine kompilierte Binärdatei ohne Proxy-Unterstützung), ist die einzig verbleibende Option eine host-spezifische statische Route:
route add <zielIp> mask 255.255.255.255 <gateway> metric 1 # benötigt Admin
route delete <zielIp> # rückgängig machen, immer
Dies ist global. Es zieht alle Prozesse für dieses Ziel aus dem Tunnel – einschließlich Ihnen, wenn Sie jemals denselben Host kontaktieren. Erfordert erhöhte Rechte, bleibt bestehen, bis es gelöscht wird, und wird leicht vergessen. Fragen Sie vor der Verwendung, und löschen Sie es in derselben Sitzung.