From b0a630390f3bd0fddd16663e31b575b9707ae560 Mon Sep 17 00:00:00 2001 From: daymade Date: Sun, 8 Feb 2026 00:26:36 +0800 Subject: [PATCH] Release v1.31.0: Add tunnel-doctor skill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add tunnel-doctor v1.0.0: diagnose and fix Tailscale + proxy/VPN route conflicts on macOS - 6-step diagnostic workflow, per-tool fix guides (Shadowrocket/Clash/Surge) - Tailscale SSH ACL config and WSL snap vs apt guidance - Update marketplace to v1.31.0, skills count 35 → 36 Co-Authored-By: Claude Opus 4.6 --- .claude-plugin/marketplace.json | 26 +++- CHANGELOG.md | 20 +++ CLAUDE.md | 7 +- README.md | 46 +++++- README.zh-CN.md | 46 +++++- tunnel-doctor/.security-scan-passed | 4 + tunnel-doctor/SKILL.md | 193 ++++++++++++++++++++++++ tunnel-doctor/references/proxy_fixes.md | 181 ++++++++++++++++++++++ 8 files changed, 513 insertions(+), 10 deletions(-) create mode 100644 tunnel-doctor/.security-scan-passed create mode 100644 tunnel-doctor/SKILL.md create mode 100644 tunnel-doctor/references/proxy_fixes.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 24bfbfe..b91ee2a 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -6,7 +6,7 @@ }, "metadata": { "description": "Professional Claude Code skills for GitHub operations, document conversion, diagram generation, statusline customization, Teams communication, repomix utilities, skill creation, CLI demo generation, LLM icon access, Cloudflare troubleshooting, UI design system extraction, professional presentation creation, YouTube video downloading, secure repomix packaging, ASR transcription correction, video comparison quality analysis, comprehensive QA testing infrastructure, prompt optimization with EARS methodology, session history recovery, documentation cleanup, format-controlled deep research report generation with evidence tracking, PDF generation with Chinese font support, CLAUDE.md progressive disclosure optimization, CCPM skill registry search and management, Promptfoo LLM evaluation framework, iOS app development with XcodeGen and SwiftUI, fact-checking with automated corrections, Twitter/X content fetching, intelligent macOS disk space recovery, skill quality review and improvement, GitHub contribution strategy, complete internationalization/localization setup, plugin/skill troubleshooting with diagnostic tools, and evidence-based competitor analysis with source citations", - "version": "1.30.0", + "version": "1.31.0", "homepage": "https://github.com/daymade/claude-code-skills" }, "plugins": [ @@ -729,6 +729,30 @@ "skills": [ "./competitors-analysis" ] + }, + { + "name": "tunnel-doctor", + "description": "Diagnose and fix route conflicts between Tailscale and proxy/VPN tools (Shadowrocket, Clash, Surge) on macOS. Use when Tailscale ping works but SSH/TCP times out, when proxy tools hijack the 100.64.0.0/10 CGNAT range, or when setting up Tailscale SSH to WSL instances", + "source": "./", + "strict": false, + "version": "1.0.0", + "category": "developer-tools", + "keywords": [ + "tailscale", + "vpn", + "shadowrocket", + "clash", + "surge", + "route-conflict", + "wsl", + "ssh", + "proxy", + "networking", + "macos" + ], + "skills": [ + "./tunnel-doctor" + ] } ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 74890d3..e34d2f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - None +## [1.31.0] - 2026-02-07 + +### Added +- **New Skill**: tunnel-doctor - Diagnose and fix Tailscale + proxy/VPN route conflicts + - 6-step diagnostic workflow for route conflict detection and resolution + - Shadowrocket, Clash, Surge proxy tool fix guides + - Tailscale SSH ACL configuration (check vs accept) + - WSL snap vs apt Tailscale installation guidance + - Bundled references: proxy_fixes.md with per-tool instructions + - Shadowrocket config API documentation + +### Changed +- Updated marketplace skills count from 35 to 36 +- Updated marketplace version from 1.30.0 to 1.31.0 +- Updated README.md badges (skills count, version) +- Updated README.md to include tunnel-doctor in skills listing +- Updated README.zh-CN.md badges (skills count, version) +- Updated README.zh-CN.md to include tunnel-doctor in skills listing +- Updated CLAUDE.md skills count from 35 to 36 + ## [1.30.0] - 2026-01-29 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index a9b286d..efd03c3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Repository Overview -This is a Claude Code skills marketplace containing 35 production-ready skills organized in a plugin marketplace structure. Each skill is a self-contained package that extends Claude's capabilities with specialized knowledge, workflows, and bundled resources. +This is a Claude Code skills marketplace containing 36 production-ready skills organized in a plugin marketplace structure. Each skill is a self-contained package that extends Claude's capabilities with specialized knowledge, workflows, and bundled resources. **Essential Skill**: `skill-creator` is the most important skill in this marketplace - it's a meta-skill that enables users to create their own skills. Always recommend it first for users interested in extending Claude Code. @@ -134,7 +134,7 @@ Skills for public distribution must NOT contain: ## Marketplace Configuration The marketplace is configured in `.claude-plugin/marketplace.json`: -- Contains 35 plugins, each mapping to one skill +- Contains 36 plugins, each mapping to one skill - Each plugin has: name, description, version, category, keywords, skills array - Marketplace metadata: name, owner, version, homepage @@ -144,7 +144,7 @@ The marketplace is configured in `.claude-plugin/marketplace.json`: 1. **Marketplace Version** (`.claude-plugin/marketplace.json` → `metadata.version`) - Tracks the marketplace catalog as a whole - - Current: v1.30.0 + - Current: v1.31.0 - Bump when: Adding/removing skills, major marketplace restructuring - Semantic versioning: MAJOR.MINOR.PATCH @@ -195,6 +195,7 @@ The marketplace is configured in `.claude-plugin/marketplace.json`: 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 **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 c597e4a..a104cbe 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,15 @@ [![简体中文](https://img.shields.io/badge/语言-简体中文-red)](./README.zh-CN.md) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![Skills](https://img.shields.io/badge/skills-35-blue.svg)](https://github.com/daymade/claude-code-skills) -[![Version](https://img.shields.io/badge/version-1.30.0-green.svg)](https://github.com/daymade/claude-code-skills) +[![Skills](https://img.shields.io/badge/skills-36-blue.svg)](https://github.com/daymade/claude-code-skills) +[![Version](https://img.shields.io/badge/version-1.31.0-green.svg)](https://github.com/daymade/claude-code-skills) [![Claude Code](https://img.shields.io/badge/Claude%20Code-2.0.13+-purple.svg)](https://claude.com/code) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md) [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/daymade/claude-code-skills/graphs/commit-activity) -Professional Claude Code skills marketplace featuring 35 production-ready skills for enhanced development workflows. +Professional Claude Code skills marketplace featuring 36 production-ready skills for enhanced development workflows. ## 📑 Table of Contents @@ -1502,6 +1502,43 @@ claude plugin install competitors-analysis@daymade-skills --- +### 36. **tunnel-doctor** - Tailscale + Proxy/VPN Route 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. + +**When to use:** +- Tailscale ping works but SSH/TCP connections time out +- Proxy tools hijack the Tailscale CGNAT range (100.64.0.0/10) +- 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 +- Per-tool fix guides for Shadowrocket, Clash, and Surge +- Tailscale SSH ACL configuration (`check` vs `accept`) +- WSL snap vs apt Tailscale installation (snap sandbox breaks SSH) +- Shadowrocket config API for automated configuration + +**Example usage:** +```bash +# Install the skill +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" +"Set up Tailscale SSH to my WSL instance" +``` + +**🎬 Live Demo** + +*Coming soon* + +📚 **Documentation**: See [tunnel-doctor/references/proxy_fixes.md](./tunnel-doctor/references/proxy_fixes.md) for per-tool fix instructions. + +--- + ## 🎬 Interactive Demo Gallery Want to see all demos in one place with click-to-enlarge functionality? Check out our [interactive demo gallery](./demos/index.html) or browse the [demos directory](./demos/). @@ -1583,6 +1620,9 @@ Use **skill-reviewer** to validate your own skills against best practices before ### For Internationalization & Localization 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. + ### For Plugin & Skill Troubleshooting Use **claude-skills-troubleshooting** to diagnose and resolve Claude Code plugin and skill configuration issues. Debug why plugins appear installed but don't show in available skills, understand the installed_plugins.json vs settings.json enabledPlugins architecture, and batch-enable missing plugins from a marketplace. Essential for marketplace maintainers debugging installation issues, developers troubleshooting skill activation, or anyone confused by the GitHub #17832 auto-enable bug. diff --git a/README.zh-CN.md b/README.zh-CN.md index a1787a7..27c4ff4 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -6,15 +6,15 @@ [![简体中文](https://img.shields.io/badge/语言-简体中文-red)](./README.zh-CN.md) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![Skills](https://img.shields.io/badge/skills-35-blue.svg)](https://github.com/daymade/claude-code-skills) -[![Version](https://img.shields.io/badge/version-1.30.0-green.svg)](https://github.com/daymade/claude-code-skills) +[![Skills](https://img.shields.io/badge/skills-36-blue.svg)](https://github.com/daymade/claude-code-skills) +[![Version](https://img.shields.io/badge/version-1.31.0-green.svg)](https://github.com/daymade/claude-code-skills) [![Claude Code](https://img.shields.io/badge/Claude%20Code-2.0.13+-purple.svg)](https://claude.com/code) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md) [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/daymade/claude-code-skills/graphs/commit-activity) -专业的 Claude Code 技能市场,提供 35 个生产就绪的技能,用于增强开发工作流。 +专业的 Claude Code 技能市场,提供 36 个生产就绪的技能,用于增强开发工作流。 ## 📑 目录 @@ -1544,6 +1544,43 @@ claude plugin install competitors-analysis@daymade-skills --- +### 36. **tunnel-doctor** - Tailscale + 代理/VPN 路由冲突修复 + +诊断和修复 macOS 上 Tailscale 与代理/VPN 工具(Shadowrocket、Clash、Surge)的路由冲突,特别针对 SSH 访问 WSL 实例的场景。 + +**使用场景:** +- Tailscale ping 正常但 SSH/TCP 连接超时 +- 代理工具劫持了 Tailscale CGNAT 网段(100.64.0.0/10) +- 设置 Tailscale SSH 到 WSL 时遇到 `operation not permitted` +- 需要让 Tailscale 和 Shadowrocket/Clash/Surge 在 macOS 上共存 + +**主要功能:** +- 6 步诊断流程:从症状识别到端到端验证 +- Root cause 分析:`tun-excluded-routes` 添加冲突的 `en0` 系统路由 +- 针对 Shadowrocket、Clash、Surge 的逐工具修复指南 +- Tailscale SSH ACL 配置(`check` vs `accept`) +- WSL snap vs apt 安装 Tailscale(snap 沙箱导致 SSH 失败) +- Shadowrocket 配置 API 用于自动化配置 + +**示例用法:** +```bash +# 安装技能 +claude plugin install tunnel-doctor@daymade-skills + +# 然后让 Claude 诊断 +"Tailscale ping 正常但 SSH 超时" +"修复 macOS 上 Tailscale 和 Shadowrocket 的路由冲突" +"设置 Tailscale SSH 到我的 WSL 实例" +``` + +**🎬 实时演示** + +*即将推出* + +📚 **文档**:参见 [tunnel-doctor/references/proxy_fixes.md](./tunnel-doctor/references/proxy_fixes.md) 了解各工具修复指南。 + +--- + ## 🎬 交互式演示画廊 想要在一个地方查看所有演示并具有点击放大功能?访问我们的[交互式演示画廊](./demos/index.html)或浏览[演示目录](./demos/)。 @@ -1625,6 +1662,9 @@ claude plugin install competitors-analysis@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 实例时特别有用。 + ### 插件与技能故障排除 使用 **claude-skills-troubleshooting** 诊断和解决 Claude Code 插件和技能配置问题。调试为什么插件显示已安装但未显示在可用技能列表中、了解 installed_plugins.json 与 settings.json enabledPlugins 架构,以及批量启用市场中缺失的插件。非常适合市场维护者调试安装问题、开发者调试技能激活,或任何对 GitHub #17832 自动启用 bug 感到困惑的人。 diff --git a/tunnel-doctor/.security-scan-passed b/tunnel-doctor/.security-scan-passed new file mode 100644 index 0000000..55a99c8 --- /dev/null +++ b/tunnel-doctor/.security-scan-passed @@ -0,0 +1,4 @@ +Security scan passed +Scanned at: 2026-02-07T13:48:30.502686 +Tool: gitleaks + pattern-based validation +Content hash: 47400fa8c80000831683a9fffb470312077582721a64f6223b1506ce270bb616 diff --git a/tunnel-doctor/SKILL.md b/tunnel-doctor/SKILL.md new file mode 100644 index 0000000..7d4dffa --- /dev/null +++ b/tunnel-doctor/SKILL.md @@ -0,0 +1,193 @@ +--- +name: tunnel-doctor +description: Diagnose and fix conflicts between Tailscale and proxy/VPN tools (Shadowrocket, Clash, Surge) on macOS. Covers two conflict types - route hijacking (proxy TUN overrides Tailscale routes) and HTTP proxy env var interception (http_proxy/NO_PROXY misconfiguration). Use when Tailscale ping works but SSH/HTTP times out, when curl to Tailscale IPs returns empty/timeout, or when setting up Tailscale SSH to WSL instances. +allowed-tools: Read, Grep, Edit, Bash +--- + +# Tunnel Doctor + +Diagnose and fix conflicts when Tailscale coexists with proxy/VPN tools on macOS, with specific guidance for SSH access to WSL instances. + +## Diagnostic Workflow + +### Step 1: Identify the Symptom + +Determine which scenario applies: + +- **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) +- **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) + +**Key distinction**: SSH does NOT use `http_proxy`/`NO_PROXY` env vars, but curl/wget/Python requests/Node.js fetch do. If SSH works but HTTP doesn't, it's almost always a proxy env var issue, not a route issue. + +### Step 2A: Fix HTTP Proxy Environment Variables + +Check if proxy env vars are intercepting Tailscale HTTP traffic: + +```bash +env | grep -i proxy +``` + +**Broken output** — proxy is set but `NO_PROXY` doesn't exclude Tailscale: +``` +http_proxy=http://127.0.0.1:1082 +https_proxy=http://127.0.0.1:1082 +NO_PROXY=localhost,127.0.0.1 ← Missing Tailscale! +``` + +**Fix** — add Tailscale MagicDNS domain + CIDR to `NO_PROXY`: + +```bash +export NO_PROXY=localhost,127.0.0.1,.ts.net,100.64.0.0/10,192.168.*,10.*,172.16.* +``` + +| Entry | Covers | Why | +|-------|--------|-----| +| `.ts.net` | MagicDNS domains (`host.tailnet.ts.net`) | Matched before DNS resolution | +| `100.64.0.0/10` | Tailscale IPs (`100.64.*` – `100.127.*`) | Precise CIDR, no public IP false positives | +| `192.168.*,10.*,172.16.*` | RFC 1918 private networks | LAN should never be proxied | + +**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. + +Verify the fix: + +```bash +# Both must return HTTP 200: +NO_PROXY="...(new value)..." curl -s --connect-timeout 5 http://.ts.net:/health -w "HTTP %{http_code}\n" +NO_PROXY="...(new value)..." curl -s --connect-timeout 5 http://:/health -w "HTTP %{http_code}\n" +``` + +Then persist in shell config (`~/.zshrc` or `~/.bashrc`). + +### Step 2B: Detect Route Conflicts + +Check if a proxy tool hijacked the Tailscale CGNAT range: + +```bash +route -n get +``` + +**Healthy output** — traffic goes through Tailscale interface: +``` +destination: 100.64.0.0 +interface: utun7 # Tailscale interface (utunN varies) +``` + +**Broken output** — proxy hijacked the route: +``` +destination: 100.64.0.0 +gateway: 192.168.x.1 # Default gateway +interface: en0 # Physical interface, NOT Tailscale +``` + +Confirm with full route table: + +```bash +netstat -rn | grep 100.64 +``` + +Two competing routes indicate a conflict: +``` +100.64/10 192.168.x.1 UGSc en0 ← Proxy added this (wins) +100.64/10 link#N UCSI utun7 ← Tailscale route (loses) +``` + +**Root cause**: On macOS, `UGSc` (Static Gateway) takes priority over `UCSI` (Cloned Static Interface) for the same prefix length. + +### 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. + +**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. + +**Universal fix** — add this rule to any proxy tool: +``` +IP-CIDR,100.64.0.0/10,DIRECT +IP-CIDR,fd7a:115c:a1e0::/48,DIRECT +``` + +After applying fixes, verify: + +```bash +route -n get +# Should show Tailscale utun interface, NOT en0 +``` + +### Step 4: Configure Tailscale SSH ACL + +If SSH connects but returns `operation not permitted`, the Tailscale ACL may require browser authentication for each connection. + +At [Tailscale ACL admin](https://login.tailscale.com/admin/acls), ensure the SSH section uses `"action": "accept"`: + +```json +"ssh": [ + { + "action": "accept", + "src": ["autogroup:member"], + "dst": ["autogroup:self"], + "users": ["autogroup:nonroot", "root"] + } +] +``` + +**Note**: `"action": "check"` requires browser authentication each time. Change to `"accept"` for non-interactive SSH access. + +### Step 5: Fix WSL Tailscale Installation + +If SSH connects and ACL passes but fails with `be-child ssh` exit code 1 in tailscaled logs, the snap-installed Tailscale has sandbox restrictions preventing SSH shell execution. + +**Diagnosis** — check WSL tailscaled logs: + +```bash +# For snap installs: +sudo journalctl -u snap.tailscale.tailscaled -n 30 --no-pager + +# For apt installs: +sudo journalctl -u tailscaled -n 30 --no-pager +``` + +Look for: +``` +access granted to user@example.com as ssh-user "username" +starting non-pty command: [/snap/tailscale/.../tailscaled be-child ssh ...] +Wait: code=1 +``` + +**Fix** — replace snap with apt installation: + +```bash +# Remove snap version +sudo snap remove tailscale + +# Install apt version +curl -fsSL https://tailscale.com/install.sh | sh + +# Start with SSH enabled +sudo tailscale up --ssh +``` + +**Important**: The new installation may assign a different Tailscale IP. Check with `tailscale status --self`. + +### Step 6: Verify End-to-End + +Run a complete connectivity test: + +```bash +# 1. Check route is correct +route -n get + +# 2. Test TCP connectivity +nc -z -w 5 22 + +# 3. Test SSH +ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no @ 'echo SSH_OK && hostname && whoami' +``` + +All three must pass. If step 1 fails, revisit Step 3. If step 2 fails, check WSL sshd or firewall. If step 3 fails, revisit Steps 4-5. + +## References + +- [references/proxy_fixes.md](references/proxy_fixes.md) — Detailed fix instructions for Shadowrocket, Clash, and Surge diff --git a/tunnel-doctor/references/proxy_fixes.md b/tunnel-doctor/references/proxy_fixes.md new file mode 100644 index 0000000..b313f3b --- /dev/null +++ b/tunnel-doctor/references/proxy_fixes.md @@ -0,0 +1,181 @@ +# Proxy Tool Fix Reference + +Detailed instructions for making each proxy tool coexist with Tailscale on macOS. + +## Contents + +- Shadowrocket (macOS ARM) +- Clash / ClashX Pro +- Surge +- NO_PROXY Environment Variable +- General Principles + +## Shadowrocket (macOS ARM) + +### The Problem + +Shadowrocket's `tun-excluded-routes` adds a system route `100.64/10 → default gateway (en0)` for each excluded CIDR. This route has higher priority (`UGSc`) than Tailscale's route (`UCSI`), hijacking all Tailscale traffic. + +### The Fix + +1. **Remove** `100.64.0.0/10` from `tun-excluded-routes` in `[General]` +2. **Add** a DIRECT rule in `[Rule]` section: + +``` +IP-CIDR,100.64.0.0/10,DIRECT +``` + +This lets Tailscale traffic enter the Shadowrocket TUN interface, where the DIRECT rule passes it through without proxying. The system route table remains clean. + +### Config API + +Shadowrocket exposes a config editor API when the **Edit Plain Text** view is open: + +```bash +# Read current config +NO_PROXY="" curl -s "http://:8080/api/read" + +# Save updated config (replaces editor buffer) +NO_PROXY="" curl -s -X POST "http://:8080/api/save" --data-binary @config.txt +``` + +**Important**: The API `save` only writes to the editor buffer. The user must click **Save** in the Shadowrocket UI to persist changes. After saving, the VPN connection must be restarted for route changes to take effect. + +### Example tun-excluded-routes (correct) + +``` +tun-excluded-routes = 10.0.0.0/8, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.88.99.0/24, 192.168.0.0/16, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 255.255.255.255/32 +``` + +Note: `100.64.0.0/10` is intentionally absent. + +## Clash / ClashX Pro + +### The Fix + +Add Tailscale CIDRs to the rules section before `MATCH`: + +```yaml +rules: + - IP-CIDR,100.64.0.0/10,DIRECT + - IP-CIDR,fd7a:115c:a1e0::/48,DIRECT + # ... other rules ... + - MATCH,PROXY +``` + +For Clash with TUN mode, also add to `tun.excluded-routes` (if TUN mode doesn't create conflicting system routes on macOS): + +```yaml +tun: + enable: true + # Only if this doesn't create conflicting system routes: + # excluded-routes: + # - 100.64.0.0/10 +``` + +Test with `route -n get 100.x.x.x` after applying to confirm no `en0` hijack. + +## Surge + +### The Fix + +Add to the `[Rule]` section: + +``` +IP-CIDR,100.64.0.0/10,DIRECT +IP-CIDR,fd7a:115c:a1e0::/48,DIRECT +``` + +In Surge's **TUN Excluded Routes** (if available), the same caveat applies as Shadowrocket: excluding `100.64.0.0/10` may add an `en0` route. Test with `route -n get` to confirm. + +Surge also supports `skip-proxy` and `always-real-ip` which may help: + +``` +[General] +skip-proxy = 100.64.0.0/10, fd7a:115c:a1e0::/48 +always-real-ip = *.ts.net +``` + +## NO_PROXY Environment Variable + +### The Problem + +Even when system routes are correct (Tailscale `utun` interface wins), HTTP clients like curl, Python requests, and Node.js fetch respect `http_proxy`/`https_proxy` env vars. If `NO_PROXY` doesn't exclude Tailscale addresses, HTTP traffic is sent to the proxy process, which may fail to reach `100.x` addresses. + +This is a **different conflict layer** from route hijacking — routes are fine, but the application bypasses them by sending traffic to the local proxy port. + +### The Fix + +```bash +export NO_PROXY=localhost,127.0.0.1,.ts.net,100.64.0.0/10,192.168.*,10.*,172.16.* +``` + +### NO_PROXY Syntax Pitfalls + +| Syntax | curl | Python requests | Node.js | Meaning | +|--------|------|-----------------|---------|---------| +| `.ts.net` | ✅ | ✅ | ✅ | Domain suffix match (correct) | +| `*.ts.net` | ❌ | ✅ | varies | Glob — curl does NOT support this | +| `100.64.0.0/10` | ✅ 7.86+ | ✅ 2.25+ | ❌ native | CIDR notation | +| `100.*` | ✅ | ✅ | ✅ | Too broad — covers public IPs `100.0-63.*` and `100.128-255.*` | + +**Key rule**: Always use `.ts.net` (leading dot, no asterisk) for domain suffix matching. This is the most portable syntax across all HTTP clients. + +### Why Not `100.*`? + +`100.0.0.0/8` includes public IP space: +- `100.0.0.0 – 100.63.255.255` — **public** IPs +- `100.64.0.0 – 100.127.255.255` — CGNAT (Tailscale uses this) +- `100.128.0.0 – 100.255.255.255` — **public** IPs + +Using `100.*` in `NO_PROXY` would bypass the proxy for services on public `100.x` IPs — potentially breaking access to GFW-blocked services that happen to use those addresses. + +### MagicDNS Recommendation + +Prefer accessing Tailscale devices by MagicDNS name (e.g., `my-server` or `my-server.tailnet.ts.net`) rather than raw IPs. This makes `.ts.net` in `NO_PROXY` the primary bypass mechanism, with `100.64.0.0/10` as a fallback for direct IP usage. + +Check MagicDNS status: +```bash +tailscale dns status +``` + +## General Principles + +### Why tun-excluded-routes Breaks Tailscale + +On macOS, when a VPN tool excludes a CIDR from its TUN interface, it typically adds a system route pointing that CIDR to the default gateway via `en0`. For `100.64.0.0/10`: + +``` +100.64/10 192.168.x.1 UGSc en0 ← VPN tool adds this +100.64/10 link#N UCSI utun7 ← Tailscale's route +``` + +macOS route priority: `UGSc` > `UCSI` for same prefix length. Result: Tailscale traffic goes to the router, which has no route to 100.x addresses. + +### The Correct Approach + +Let Tailscale traffic enter the VPN TUN interface, then use an application-layer DIRECT/bypass rule to send it out without proxying. This avoids polluting the system route table. + +### Quick Verification + +After any fix, always verify: + +```bash +# Route should go through Tailscale utun, not en0 +route -n get + +# Should show only one 100.64/10 route (Tailscale's) +netstat -rn | grep 100.64 +``` + +### Emergency Rollback + +If a proxy config change breaks other connectivity: + +```bash +# Restart the proxy tool (Shadowrocket/Clash/Surge) +# This restores its default routes + +# Or manually delete a conflicting route: +sudo route delete -net 100.64.0.0/10 +```