- Skill ID
- daymade/claude-code-skills/tunnel-doctor
- Publisher
- daymade
- Repository
- claude-code-skills
- Installs
- 0
- Files
- 7
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
daymade/claude-code-skills/tunnel-doctorInstalls these files- SKILL.md
- references/dns_resolver_chain_stall.md
- references/network_change_recovery.md
- references/proxy_conflict_reference.md
- references/proxy_node_chain_throughput.md
- references/windows_host_tun_wsl_cascade.md
- scripts/quick_diagnose.py
What this skill tells the agent
Tunnel Doctor
Diagnose and fix conflicts when Tailscale coexists with proxy/VPN tools on macOS, with specific guidance for SSH access to WSL instances.
Methodology base: the general diagnostic discipline this skill builds on — evidence over assumption, falsification over confirmation, layered isolation, counter-review — lives in the debugging-network-issues skill. This skill is the macOS Tailscale⨯proxy domain layer on top of it; reach for the base skill when the symptom is not a known Tailscale/proxy conflict.
Ownership boundary: this skill owns concrete local network-path operations: Tailscale, route/DNS/proxy interception, VM/WSL propagation, TUN forwarding planes, and proxy node/exit/chain capacity. Use debugging-network-issues as the general method when the boundary is still unknown or the symptom belongs to SSE/CDN/application protocol behavior. This keeps one concrete operator instead of forcing the user to choose between two overlapping proxy doctors.
Target and task scope
Before remote probes or changes, establish whether the target is a designated test machine, an explicitly requested colleague's working computer, or unknown. Use the owner's existing machine-purpose ledger and current task; do not log into a colleague's machine to classify it. Saved SSH access and previous successful tests do not grant ongoing use. Use designated test machines for routine testing; their unavailability does not authorize another person's computer.
Keep an explicitly requested one-off test on a colleague's computer within its stated result and necessary verification. Stop there on completion, cancellation, or a need for an unapproved environment change. Move later performance, migration, and regression tests to designated test machines. A test failure does not authorize disabling that person's proxy/VPN, quitting apps, changing routes, or installing a background task. Proceed with disruptive repair there only when the user has explicitly requested that repair and its interruption. Existing authorization for owner test-machine maintenance remains valid; do not ask again for its routine steps.
Apply this boundary even when invoked directly, through another Skill, after compaction, or through a peer handoff. After access is stopped, use existing records rather than another SSH probe to verify that it stopped.
Disruptive network changes
Before any authorized VPN disconnect, app termination, route cutover, or service restart, read network_change_recovery.md. Validate prerequisites before interruption, arm bounded recovery before the first disruptive action, and verify both the repaired path and the user's original network use. A successful stop command, a detached process, or a restart placed at the end of a script is not recovery evidence.
Conflict Layers
Proxy/VPN tools on macOS create conflicts at several independent layers. Layers 1-3 affect Tailscale connectivity; Layer 4 affects SSH git operations; Layer 5 affects VM/container runtimes. TUN-state failure modes beyond this table — SSH/git connection drops, resolver stall, DIRECT split-brain — are covered in Steps 2H–2J:
| Layer | What breaks | What still works | Root cause |
|---|---|---|---|
| 1. Route table | Everything (SSH, curl, browser) | tailscale ping | tun-excluded-routes adds en0 route overriding Tailscale utun |
| 2. HTTP env vars | curl, Python requests, Node.js fetch | SSH, browser | http_proxy set without NO_PROXY for Tailscale |
| 3. System proxy (browser) | Browser only (HTTP 503) | SSH, curl (both with/without proxy) | Browser uses VPN system proxy; DIRECT rule routes via Wi-Fi, not Tailscale utun |
| 4. SSH ProxyCommand double tunnel | git push/pull (intermittent) | ssh -T (small data) | connect -H creates HTTP CONNECT tunnel redundant with Shadowrocket TUN; landing proxy drops large/long-lived transfers |
| 5. VM/Container proxy propagation | docker pull, docker build | Host curl, running containers | VM runtime (OrbStack/Docker Desktop) auto-injects or caches proxy config; removing proxy makes it worse (VM traffic via TUN → TLS timeout) |
Diagnostic Workflow
Step 1: Identify the Symptom
Determine which scenario applies:
- Browser returns HTTP 503, but `curl` and SSH both work → System proxy bypass conflict (Step 2C)
- `local.<domain>` fails in browser/default `curl`, but direct/no-proxy request works → Local vanity domain proxy interception (Step 2C-1)
- Tailscale ping works, SSH works, but curl/HTTP times out → HTTP proxy env var conflict (Step 2A)
- Tailscale ping works, SSH/TCP times out → Route conflict (Step 2B)
- Remote dev server auth redirects to `localhost` → browser can't follow → SSH tunnel needed (Step 2D)
- `make status` / scripts curl to localhost fail with proxy → localhost proxy interception (Step 2E)
- `git push/pull` fails with `FATAL: failed to begin relaying via HTTP` → SSH double tunnel (Step 2F)
- `docker build` `RUN apk/apt` fails with `Connection refused` instantly → OrbStack transparent proxy + TUN conflict (Step 2G-1, fix:
--network host) - `docker pull` fails with `TLS handshake timeout` → VM proxy misconfiguration (Step 2G-2, fix:
docker.jsonwithhost.internal) - Container healthcheck `(unhealthy)` but app runs fine → Lowercase proxy env var leak (Step 2G-4, fix: clear
http_proxy+HTTP_PROXY) - `docker build` can't fetch base images → VM/container proxy propagation (Step 2G)
- `docker pull` works but `docker build` still dies fetching base-image tokens (TLS/i-o timeout) on a WSL2 + Docker Desktop host, or every runbook proxy port on a Windows+v2rayN host silently died after a v2rayN upgrade → buildkit direct-dials past the DD proxy override / v2rayN ≥7.17 LAN-port split (references/windows_host_tun_wsl_cascade.md §2026-08-23)
- `git clone` fails with `Connection closed by 198.18.x.x` → two different mechanisms produce this; Step 2H separates them
- Every domestic/DIRECT-rule site fails at once (TLS `unexpected EOF` mid-handshake, proxy-port CONNECT returns 503, Node CLIs report `UNKNOWN_CERTIFICATE_VERIFICATION_ERROR`) while proxied overseas sites keep working → TUN DIRECT split-brain (Step 2J)
- Everything on macOS fails at once — domestic AND overseas, and even Step 2J's real-IP probe fails → do not declare an outage yet; run the physical-interface discriminator in "TUN full-stall vs genuine outage" (above Step 2A)
- SSH connects but `operation not permitted` → Tailscale SSH config issue (Step 4)
- SSH connects but `be-child ssh` exits code 1 → WSL snap sandbox issue (Step 5)
- TCP port 22 reachable (`nc -z` succeeds) but SSH fails with `kex_exchange_identification: Connection closed` → Tailscale SSH proxy intercept on WSL (Step 5A)
- Same `kex_exchange_identification` / `Connection closed by UNKNOWN port 65535`, but there is no Tailscale — you are behind a TUN and the host is a public cloud VM whose HTTPS still works → could be your TUN or the destination's firewall allowlist; they are indistinguishable from the client. Step 2K settles it out-of-band
- `tailscale ssh` returns "not available on App Store builds" → Wrong Tailscale distribution on macOS (Step 5B)
- Any tool using system DNS (`ssh`, `curl`, `git`) hangs ~60s before resolving, but `nslookup` returns instantly → Stalled resolver in
getaddrinfochain (Step 2I) - Windows+WSL host: everything offline at once (domestic AND overseas), WSL dead too, "even Tailscale won't come online" — and/or the user tried several recovery actions (switched NICs, toggled TUN) and can't tell which one fixed it → Windows host TUN cascade + event-log forensics (Step 5C)
More from daymade
Use this skill in a project
Open any RiverX project, search the Skills panel for daymade/claude-code-skills/tunnel-doctor, and install it in one click.
