diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index f08d237..5a037a9 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -732,10 +732,10 @@ }, { "name": "tunnel-doctor", - "description": "Diagnoses and fixes conflicts between Tailscale and proxy/VPN tools (Shadowrocket, Clash, Surge) on macOS. Covers three conflict layers: route hijacking, HTTP proxy env var interception, and system proxy bypass. Includes SOP for remote development via SSH tunnels with proxy-safe Makefile patterns. Use when Tailscale ping works but SSH/HTTP times out, when browser returns 503 but curl works, when setting up Tailscale SSH to WSL instances, or when bootstrapping remote dev environments over Tailscale", + "description": "Diagnoses and fixes conflicts between Tailscale and proxy/VPN tools (Shadowrocket, Clash, Surge) on macOS. Covers four conflict layers: route hijacking, HTTP proxy env var interception, system proxy bypass, and SSH ProxyCommand double tunneling. Includes SOP for remote development via SSH tunnels with proxy-safe Makefile patterns. Use when Tailscale ping works but SSH/HTTP times out, when browser returns 503 but curl works, when git push fails with failed to begin relaying via HTTP, when setting up Tailscale SSH to WSL instances, or when bootstrapping remote dev environments over Tailscale", "source": "./", "strict": false, - "version": "1.1.0", + "version": "1.2.0", "category": "developer-tools", "keywords": [ "tailscale", @@ -749,6 +749,8 @@ "ssh-tunnel", "autossh", "proxy", + "proxycommand", + "git-push", "networking", "macos", "makefile", diff --git a/CHANGELOG.md b/CHANGELOG.md index f20e05a..fe881a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - None +## [1.33.1] - 2026-02-17 + +### Changed +- **tunnel-doctor** v1.1.0 → v1.2.0: Add Layer 4 SSH ProxyCommand double tunnel diagnostics + - New conflict layer: SSH ProxyCommand double tunneling causing intermittent git push/pull failures + - New diagnostic step 2F: detect and fix redundant HTTP CONNECT tunnel when Shadowrocket TUN is active + - Structural improvements per skill best practices: + - Eliminate content duplication between SKILL.md and reference (73 → 27 lines) + - Rename `proxy_fixes.md` → `proxy_conflict_reference.md` for clarity + - Trim SKILL.md to 487 lines (under 500 limit) + - Fix "apply all four" listing 5 items (separate anti-pattern warning) + - Clarify Layer 4's relationship to Tailscale theme + ## [1.33.0] - 2026-02-16 ### Changed diff --git a/CLAUDE.md b/CLAUDE.md index 9ddfc4d..693e9cf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -212,7 +212,7 @@ This applies when you change ANY file under a skill directory: 33. **meeting-minutes-taker** - Transform meeting transcripts into structured minutes with multi-pass generation, speaker quotes, and iterative human review 34. **deep-research** - Generate format-controlled research reports with evidence mapping, citations, and multi-pass synthesis 35. **competitors-analysis** - Evidence-based competitor tracking and analysis with source citations (file:line_number format) -36. **tunnel-doctor** - Diagnose and fix Tailscale + proxy/VPN route conflicts on macOS with WSL SSH support +36. **tunnel-doctor** - Diagnose and fix Tailscale + proxy/VPN conflicts (four layers: route, HTTP env, system proxy, SSH ProxyCommand) on macOS with WSL SSH support 37. **windows-remote-desktop-connection-doctor** - Diagnose AVD/W365 connection quality issues with transport protocol analysis and Windows App log parsing **Recommendation**: Always suggest `skill-creator` first for users interested in creating skills or extending Claude Code. diff --git a/README.md b/README.md index 0897db5..541267f 100644 --- a/README.md +++ b/README.md @@ -1505,23 +1505,25 @@ claude plugin install competitors-analysis@daymade-skills --- -### 36. **tunnel-doctor** - Tailscale + Proxy/VPN Route Conflict Fixer +### 36. **tunnel-doctor** - Tailscale + Proxy/VPN Conflict Fixer -Diagnose and fix route conflicts when using Tailscale alongside proxy/VPN tools (Shadowrocket, Clash, Surge) on macOS, with specific guidance for SSH access to WSL instances. +Diagnose and fix conflicts when using Tailscale alongside proxy/VPN tools (Shadowrocket, Clash, Surge) on macOS. Covers four independent conflict layers with specific guidance for SSH access to WSL instances. **When to use:** - Tailscale ping works but SSH/TCP connections time out - Proxy tools hijack the Tailscale CGNAT range (100.64.0.0/10) +- Browser returns HTTP 503 but curl and SSH work +- `git push/pull` fails with "failed to begin relaying via HTTP" - Setting up Tailscale SSH to WSL and encountering `operation not permitted` - Need to make Tailscale and Shadowrocket/Clash/Surge coexist on macOS **Key features:** -- 6-step diagnostic workflow from symptom identification to end-to-end verification -- Root cause analysis: `tun-excluded-routes` adds conflicting `en0` system routes +- Four-layer diagnostic model: route hijacking, HTTP env vars, system proxy bypass, SSH ProxyCommand double tunneling - Per-tool fix guides for Shadowrocket, Clash, and Surge +- SSH ProxyCommand double tunnel detection and fix (git push/pull failures) - Tailscale SSH ACL configuration (`check` vs `accept`) - WSL snap vs apt Tailscale installation (snap sandbox breaks SSH) -- Shadowrocket config API for automated configuration +- Remote development SOP with proxy-safe Makefile patterns **Example usage:** ```bash @@ -1531,6 +1533,7 @@ claude plugin install tunnel-doctor@daymade-skills # Then ask Claude to diagnose "Tailscale ping works but SSH times out" "Fix Tailscale and Shadowrocket route conflict on macOS" +"git push fails with failed to begin relaying via HTTP" "Set up Tailscale SSH to my WSL instance" ``` @@ -1538,7 +1541,7 @@ claude plugin install tunnel-doctor@daymade-skills *Coming soon* -📚 **Documentation**: See [tunnel-doctor/references/proxy_fixes.md](./tunnel-doctor/references/proxy_fixes.md) for per-tool fix instructions. +📚 **Documentation**: See [tunnel-doctor/references/proxy_conflict_reference.md](./tunnel-doctor/references/proxy_conflict_reference.md) for per-tool configuration and conflict architecture. --- @@ -1663,7 +1666,7 @@ Use **skill-reviewer** to validate your own skills against best practices before Use **i18n-expert** to set up complete i18n infrastructure for React/Next.js/Vue applications, audit existing implementations for missing translation keys, and ensure locale parity between en-US and zh-CN. Perfect for teams launching products to global markets, maintaining multi-language UIs, or replacing hard-coded strings with proper i18n keys. Combine with **skill-creator** to create locale-aware skills, or with **docs-cleaner** to consolidate documentation across multiple languages. ### For Network & VPN Troubleshooting -Use **tunnel-doctor** to diagnose and fix route conflicts between Tailscale and proxy/VPN tools on macOS. Essential when Tailscale ping works but TCP connections fail, or when setting up Tailscale SSH to WSL instances alongside Shadowrocket, Clash, or Surge. +Use **tunnel-doctor** to diagnose and fix conflicts between Tailscale and proxy/VPN tools on macOS across four independent layers (route hijacking, HTTP env vars, system proxy, SSH ProxyCommand). Essential when Tailscale ping works but TCP connections fail, when git push fails with "failed to begin relaying via HTTP", or when setting up Tailscale SSH to WSL instances alongside Shadowrocket, Clash, or Surge. ### For Remote Desktop & VDI Optimization Use **windows-remote-desktop-connection-doctor** to diagnose Azure Virtual Desktop / W365 connection quality issues on macOS. Essential when transport shows WebSocket instead of UDP Shortpath, when RTT is unexpectedly high, or when RDP Shortpath fails after changing network locations. Combines network evidence gathering with Windows App log analysis for systematic root cause identification. diff --git a/README.zh-CN.md b/README.zh-CN.md index 84e8fac..c4ac16b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1547,23 +1547,25 @@ claude plugin install competitors-analysis@daymade-skills --- -### 36. **tunnel-doctor** - Tailscale + 代理/VPN 路由冲突修复 +### 36. **tunnel-doctor** - Tailscale + 代理/VPN 冲突修复 -诊断和修复 macOS 上 Tailscale 与代理/VPN 工具(Shadowrocket、Clash、Surge)的路由冲突,特别针对 SSH 访问 WSL 实例的场景。 +诊断和修复 macOS 上 Tailscale 与代理/VPN 工具(Shadowrocket、Clash、Surge)的冲突。覆盖四个独立冲突层,特别针对 SSH 访问 WSL 实例的场景。 **使用场景:** - Tailscale ping 正常但 SSH/TCP 连接超时 - 代理工具劫持了 Tailscale CGNAT 网段(100.64.0.0/10) +- 浏览器返回 HTTP 503 但 curl 和 SSH 正常 +- `git push/pull` 失败并报 "failed to begin relaying via HTTP" - 设置 Tailscale SSH 到 WSL 时遇到 `operation not permitted` - 需要让 Tailscale 和 Shadowrocket/Clash/Surge 在 macOS 上共存 **主要功能:** -- 6 步诊断流程:从症状识别到端到端验证 -- Root cause 分析:`tun-excluded-routes` 添加冲突的 `en0` 系统路由 +- 四层诊断模型:路由劫持、HTTP 环境变量、系统代理绕过、SSH ProxyCommand 双重隧道 - 针对 Shadowrocket、Clash、Surge 的逐工具修复指南 +- SSH ProxyCommand 双重隧道检测与修复(git push/pull 失败) - Tailscale SSH ACL 配置(`check` vs `accept`) - WSL snap vs apt 安装 Tailscale(snap 沙箱导致 SSH 失败) -- Shadowrocket 配置 API 用于自动化配置 +- 远程开发 SOP 与代理安全的 Makefile 模式 **示例用法:** ```bash @@ -1573,6 +1575,7 @@ claude plugin install tunnel-doctor@daymade-skills # 然后让 Claude 诊断 "Tailscale ping 正常但 SSH 超时" "修复 macOS 上 Tailscale 和 Shadowrocket 的路由冲突" +"git push 失败 failed to begin relaying via HTTP" "设置 Tailscale SSH 到我的 WSL 实例" ``` @@ -1580,7 +1583,7 @@ claude plugin install tunnel-doctor@daymade-skills *即将推出* -📚 **文档**:参见 [tunnel-doctor/references/proxy_fixes.md](./tunnel-doctor/references/proxy_fixes.md) 了解各工具修复指南。 +📚 **文档**:参见 [tunnel-doctor/references/proxy_conflict_reference.md](./tunnel-doctor/references/proxy_conflict_reference.md) 了解各工具配置与冲突架构。 --- @@ -1705,7 +1708,7 @@ claude plugin install windows-remote-desktop-connection-doctor@daymade-skills 使用 **i18n-expert** 为 React/Next.js/Vue 应用程序设置完整的 i18n 基础设施、审计现有实现中缺失的翻译键,并确保 en-US 和 zh-CN 之间的语言环境一致性。非常适合向全球市场推出产品的团队、维护多语言 UI,或将硬编码字符串替换为正确的 i18n 键。与 **skill-creator** 结合使用可创建支持语言环境的技能,或与 **docs-cleaner** 结合使用可整合多种语言的文档。 ### 网络与 VPN 故障排查 -使用 **tunnel-doctor** 诊断和修复 macOS 上 Tailscale 与代理/VPN 工具的路由冲突。当 Tailscale ping 正常但 TCP 连接失败,或在使用 Shadowrocket、Clash、Surge 的同时设置 Tailscale SSH 到 WSL 实例时特别有用。 +使用 **tunnel-doctor** 诊断和修复 macOS 上 Tailscale 与代理/VPN 工具的四层冲突(路由劫持、HTTP 环境变量、系统代理、SSH ProxyCommand)。当 Tailscale ping 正常但 TCP 连接失败、git push 报 "failed to begin relaying via HTTP",或在使用 Shadowrocket、Clash、Surge 的同时设置 Tailscale SSH 到 WSL 实例时特别有用。 ### 远程桌面与 VDI 优化 使用 **windows-remote-desktop-connection-doctor** 诊断 macOS 上 Azure Virtual Desktop / W365 连接质量问题。当传输协议显示 WebSocket 而非 UDP Shortpath、RTT 异常高,或更换网络位置后 RDP Shortpath 失败时特别有用。结合网络证据收集与 Windows App 日志分析,系统性定位根因。 diff --git a/tunnel-doctor/SKILL.md b/tunnel-doctor/SKILL.md index bcf6b99..7c5a6a1 100644 --- a/tunnel-doctor/SKILL.md +++ b/tunnel-doctor/SKILL.md @@ -1,6 +1,6 @@ --- name: tunnel-doctor -description: Diagnoses and fixes conflicts between Tailscale and proxy/VPN tools (Shadowrocket, Clash, Surge) on macOS. Covers three conflict layers - (1) route hijacking (proxy TUN overrides Tailscale routes), (2) HTTP proxy env var interception (http_proxy/NO_PROXY misconfiguration), and (3) system proxy bypass (browser goes through VPN proxy, DIRECT rule can't reach Tailscale utun). Includes SOP for remote development via SSH tunnels with proxy-safe Makefile patterns. Use when Tailscale ping works but SSH/HTTP times out, when browser returns 503 but curl works, when setting up Tailscale SSH to WSL instances, or when bootstrapping remote dev environments over Tailscale. +description: Diagnoses and fixes conflicts between Tailscale and proxy/VPN tools (Shadowrocket, Clash, Surge) on macOS. Covers four conflict layers - (1) route hijacking, (2) HTTP proxy env var interception, (3) system proxy bypass, and (4) SSH ProxyCommand double tunneling causing git push/pull failures. Includes SOP for remote development via SSH tunnels with proxy-safe Makefile patterns. Use when Tailscale ping works but SSH/HTTP times out, when browser returns 503 but curl works, when git push fails with "failed to begin relaying via HTTP", when setting up Tailscale SSH to WSL instances, or when bootstrapping remote dev environments over Tailscale. allowed-tools: Read, Grep, Edit, Bash --- @@ -8,15 +8,16 @@ allowed-tools: Read, Grep, Edit, Bash Diagnose and fix conflicts when Tailscale coexists with proxy/VPN tools on macOS, with specific guidance for SSH access to WSL instances. -## Three Conflict Layers +## Four Conflict Layers -Tailscale + proxy tools can conflict at three independent layers. Each has different symptoms: +Proxy/VPN tools on macOS create conflicts at four independent layers. Layers 1-3 affect Tailscale connectivity; Layer 4 affects SSH git operations (same proxy environment, different target): | 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 | ## Diagnostic Workflow @@ -29,6 +30,7 @@ Determine which scenario applies: - **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) - **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) @@ -36,6 +38,7 @@ Determine which scenario applies: - SSH does NOT use `http_proxy`/`NO_PROXY` env vars. If SSH works but HTTP doesn't → Layer 2. - `curl` uses `http_proxy` env var, NOT the system proxy. Browser uses system proxy (set by VPN). If `curl` works but browser doesn't → Layer 3. - If `tailscale ping` works but regular `ping` doesn't → Layer 1 (route table corrupted). +- If `ssh -T git@github.com` works but `git push` fails intermittently → Layer 4 (double tunnel). ### Step 2A: Fix HTTP Proxy Environment Variables @@ -66,7 +69,7 @@ export NO_PROXY=localhost,127.0.0.1,.ts.net,100.64.0.0/10,192.168.*,10.*,172.16. **Two layers complement each other**: `.ts.net` handles domain-based access, `100.64.0.0/10` handles direct IP access. -**NO_PROXY syntax pitfalls** — see [references/proxy_fixes.md](references/proxy_fixes.md) for the compatibility matrix. +**NO_PROXY syntax pitfalls** — see [references/proxy_conflict_reference.md](references/proxy_conflict_reference.md) for the compatibility matrix. Verify the fix: @@ -196,9 +199,37 @@ Alternatively, set `no_proxy` globally in `~/.zshrc`: export no_proxy=localhost,127.0.0.1 ``` +### Step 2F: Fix SSH ProxyCommand Double Tunnel (git push/pull failures) + +**Symptom**: `ssh -T git@github.com` succeeds consistently, but `git push` or `git pull` fails intermittently with: + +``` +FATAL: failed to begin relaying via HTTP. +Connection closed by UNKNOWN port 65535 +``` + +Small operations (auth, fetch metadata) work; large data transfers fail. + +**Root cause**: When Shadowrocket TUN is active, it already routes all TCP traffic through its VPN tunnel. If SSH config also uses `ProxyCommand connect -H`, data flows through two proxy layers — the landing proxy drops large/long-lived HTTP CONNECT connections. + +**Diagnosis**: + +```bash +# 1. Confirm Shadowrocket TUN is active +ifconfig | grep '^utun' + +# 2. Check SSH config for ProxyCommand +grep -A5 'Host github.com' ~/.ssh/config + +# 3. Confirm: removing ProxyCommand fixes push +GIT_SSH_COMMAND="ssh -o ProxyCommand=none" git push origin main +``` + +**Fix** — remove ProxyCommand and switch to `ssh.github.com:443`. See [references/proxy_conflict_reference.md § SSH ProxyCommand and Git Operations](references/proxy_conflict_reference.md) for the full SSH config, why port 443 helps, and fallback options when VPN is off. + ### Step 3: Fix Proxy Tool Configuration -Identify the proxy tool and apply the appropriate fix. See [references/proxy_fixes.md](references/proxy_fixes.md) for detailed instructions per tool. +Identify the proxy tool and apply the appropriate fix. See [references/proxy_conflict_reference.md](references/proxy_conflict_reference.md) for detailed instructions per tool. **Key principle**: Do NOT use `tun-excluded-routes` to exclude `100.64.0.0/10`. This causes the proxy to add a `→ en0` route that overrides Tailscale. Instead, let the traffic enter the proxy TUN and use a DIRECT rule to pass it through. @@ -374,7 +405,7 @@ Each `-L` flag is independent. If one port is already bound locally, `ExitOnForw ### 4. SSH Non-Login Shell Setup -SSH non-login shells don't load `~/.zshrc`, so nvm/Homebrew tools and proxy env vars are unavailable. Prefix all remote commands with `source ~/.zshrc 2>/dev/null;`. See [references/proxy_fixes.md § SSH Non-Login Shell Pitfall](references/proxy_fixes.md) for details and examples. +SSH non-login shells don't load `~/.zshrc`, so nvm/Homebrew tools and proxy env vars are unavailable. Prefix all remote commands with `source ~/.zshrc 2>/dev/null;`. See [references/proxy_conflict_reference.md § SSH Non-Login Shell Pitfall](references/proxy_conflict_reference.md) for details and examples. For Makefile targets that run remote commands: @@ -453,4 +484,4 @@ Before starting remote development, verify: ## References -- [references/proxy_fixes.md](references/proxy_fixes.md) — Detailed fix instructions for Shadowrocket, Clash, and Surge +- [references/proxy_conflict_reference.md](references/proxy_conflict_reference.md) — Per-tool configuration (Shadowrocket, Clash, Surge), NO_PROXY syntax, SSH ProxyCommand, and conflict architecture diff --git a/tunnel-doctor/references/proxy_fixes.md b/tunnel-doctor/references/proxy_conflict_reference.md similarity index 72% rename from tunnel-doctor/references/proxy_fixes.md rename to tunnel-doctor/references/proxy_conflict_reference.md index 07fc213..03f35e3 100644 --- a/tunnel-doctor/references/proxy_fixes.md +++ b/tunnel-doctor/references/proxy_conflict_reference.md @@ -178,17 +178,120 @@ Check MagicDNS status: tailscale dns status ``` +## SSH ProxyCommand and Git Operations + +### The Problem + +Many developers in China configure SSH with `ProxyCommand connect -H 127.0.0.1:` to tunnel SSH through their HTTP proxy. This works fine for interactive SSH and small operations. But when Shadowrocket (or Clash/Surge) runs in TUN mode, this creates a **double tunnel**: + +1. `connect -H` creates an HTTP CONNECT tunnel to the local proxy port +2. Shadowrocket TUN captures the same traffic at the system level + +The landing proxy sees a long-lived HTTP CONNECT connection and may drop it during large data transfers (`git push`, `git clone` of large repos). + +### Data Flow Comparison + +``` +Double tunnel (broken): +SSH → connect -H (HTTP CONNECT tunnel) → Shadowrocket local port 1082 + → Shadowrocket TUN → landing proxy → GitHub + +Single tunnel (correct): +SSH → system network stack → Shadowrocket TUN → landing proxy → GitHub +``` + +The HTTP CONNECT tunnel adds protocol framing overhead. The landing proxy (落地代理) sees a long-lived HTTP CONNECT connection and may apply aggressive timeouts or buffer limits, dropping the connection during large transfers. + +### Detecting TUN Mode + +```bash +# If utun interfaces exist (other than Tailscale's), a VPN TUN is active +ifconfig | grep '^utun' +``` + +If Shadowrocket/Clash/Surge TUN is active, `ProxyCommand connect -H` is redundant. + +### The Fix — SSH over Port 443 without ProxyCommand + +```bash +# 1. Add ssh.github.com host key +ssh-keyscan -p 443 ssh.github.com >> ~/.ssh/known_hosts + +# 2. Update ~/.ssh/config +``` + +``` +Host github.com + HostName ssh.github.com + Port 443 + User git + # No ProxyCommand — Shadowrocket TUN handles routing at the system level. + # Port 443 gets longer timeouts from landing proxies than port 22. + ServerAliveInterval 60 + ServerAliveCountMax 3 + IdentityFile ~/.ssh/id_ed25519 +``` + +### Why Port 443 + +HTTP proxies (and landing proxies) are optimized for port 443 traffic: +- **Longer connection timeouts**: HTTPS connections are expected to be long-lived (WebSocket, streaming, large file downloads) +- **Larger buffer limits**: Proxies allocate more resources for 443 traffic +- **No protocol inspection**: Port 22 may trigger deep packet inspection on some proxies; 443 is treated as opaque TLS + +GitHub officially supports SSH on port 443 via `ssh.github.com` — it's the same service, same authentication, different port. + +### Fallback When VPN Is Off + +Without Shadowrocket TUN, SSH can't reach GitHub directly from China. Options: + +1. **Keep old config as comment** — manually uncomment ProxyCommand when needed +2. **Use Match directive** — conditionally apply ProxyCommand (advanced): + +``` +Host github.com + HostName ssh.github.com + Port 443 + User git + ServerAliveInterval 60 + ServerAliveCountMax 3 + IdentityFile ~/.ssh/id_ed25519 + +# Uncomment when Shadowrocket is off: +# ProxyCommand /opt/homebrew/bin/connect -H 127.0.0.1:1082 %h %p +``` + +### Verification + +```bash +# Auth test +ssh -T git@github.com +# → Hi username! You've successfully authenticated... + +# Verbose — confirm ssh.github.com:443 +ssh -v -T git@github.com 2>&1 | grep 'Connecting to' +# → Connecting to ssh.github.com [20.205.243.160] port 443. + +# Large transfer test +cd /path/to/repo && git push origin main +``` + +### Performance Trade-off + +Connection setup is slightly slower (~6s vs ~2s) because TUN routing has more network hops than a direct HTTP CONNECT tunnel. Actual data transfer speed is the same (bottlenecked by bandwidth, not connection setup). + ## General Principles -### Three Conflict Layers +### Four Conflict Layers -Proxy tools and Tailscale can conflict at three independent layers on macOS: +Proxy tools create conflicts at four independent layers on macOS. Layers 1-3 affect Tailscale connectivity; Layer 4 affects SSH git operations through the same proxy infrastructure: | Layer | Setting | What it controls | Symptom when wrong | |-------|---------|------------------|--------------------| | 1. Route table | `tun-excluded-routes` | OS-level IP routing | Everything broken (SSH, curl, browser). `tailscale ping` works but `ping` doesn't | | 2. HTTP env vars | `http_proxy` / `NO_PROXY` | CLI tools (curl, wget, Python, Node.js) | `curl` times out, SSH works, browser works | | 3. System proxy | `skip-proxy` | Browser and system HTTP clients | Browser 503, `curl` works (both with/without proxy), SSH works | +| 4. SSH ProxyCommand | `ProxyCommand connect -H` | SSH git operations (push/pull/clone) | `ssh -T` works, `git push` fails intermittently with `failed to begin relaying via HTTP` | **Each layer is independent.** A fix at one layer doesn't help the others. You may need fixes at multiple layers simultaneously. @@ -218,12 +321,14 @@ Adding `100.64.0.0/10` to `skip-proxy` makes the system bypass the proxy entirel ### The Correct Approach -For full Tailscale compatibility with proxy tools, apply all three: +For full Tailscale compatibility with proxy tools, apply all four fixes: 1. **`[Rule]`**: `IP-CIDR,100.64.0.0/10,DIRECT` — handles TUN-level traffic 2. **`skip-proxy`**: Add `100.64.0.0/10` — fixes browser access 3. **`NO_PROXY` env var**: Add `100.64.0.0/10,.ts.net` — fixes CLI HTTP tools -4. **`tun-excluded-routes`**: Do NOT add `100.64.0.0/10` — this breaks everything +4. **SSH `~/.ssh/config`**: Remove `ProxyCommand`, use `ssh.github.com:443` — fixes git push/pull + +**Critical anti-pattern**: Do NOT add `100.64.0.0/10` to `tun-excluded-routes` — this breaks everything (see "Why tun-excluded-routes Breaks Tailscale" above). ### Quick Verification