重要
代理的本质是"中间人转发"——客户端不直接连目标,而是通过代理服务器中转。不同代理模式决定了哪些流量被拦截、哪些工具需要额外配置。
核心认知:不是所有工具都遵守系统代理设置。 Git、Docker、APT 等底层工具默认不读系统代理变量,需要单独配置或在网络层(TUN 模式)拦截。
1. 代理原理
1.1 代理在协议栈中的位置
| |
| 代理类型 | 工作层 | 能代理的协议 | 是否需要应用支持 | 典型端口 |
|---|---|---|---|---|
| HTTP 代理 | 应用层 | HTTP/HTTPS | 需要应用设置 http_proxy | 10800 |
| SOCKS5 代理 | 传输层 | 任意 TCP/UDP | 需要应用设置 all_proxy | 1088 |
| TUN 模式 | 网络层 | 所有 IP 流量 | 不需要——创建虚拟网卡,系统级拦截 | 无端口 |
1.2 HTTP 代理 vs SOCKS5 代理
| |
关键区别:
| HTTP 代理 | SOCKS5 | |
|---|---|---|
| 协议感知 | 理解 HTTP,可做缓存、过滤 | 不关心上层协议 |
| UDP 支持 | 不支持(仅 TCP) | 支持 UDP |
| 认证方式 | Basic Auth | 用户名/密码、GSSAPI |
| DNS 解析 | 代理服务器端解析 | 可客户端解析也可服务端解析 |
1.3 环境变量机制
| |
环境变量的工作原理:库层面的拦截。curl、wget、Python requests、Node.js axios 等网络库在发起连接前检查这些环境变量,如果设置了就通过代理连接而非直连。
但 Git、Docker CLI、APT 等工具的底层网络库不自动读取这些变量——它们通过自己的配置文件或系统服务管理来设置代理。
2. TUN 模式:从应用层代理到网络层拦截
2.1 系统代理的局限
系统代理(System Proxy)通过操作系统设置 HTTP_PROXY / HTTPS_PROXY,但只有遵守系统代理 API 的应用才会使用。以下工具默认不走系统代理:
| 工具 | 原因 |
|---|---|
| Git | 使用 libcurl,但不读系统代理设置 |
| Docker daemon | systemd 服务,环境变量在 unit file 中独立配置 |
| APT | 读 /etc/apt/apt.conf.d/proxy.conf,不读环境变量 |
| ping / traceroute | 网络层工具,不使用 HTTP/SOCKS 代理 |
2.2 TUN 模式原理
TUN 是 Linux 内核的三层虚拟网络设备。代理客户端(如 Clash)创建一个 TUN 网卡,修改系统路由表,将所有(或部分)IP 流量导向 TUN 设备。代理客户端从 TUN 设备读取 IP 包,解析出 TCP/UDP 连接,再通过代理服务器转发。
| |
TUN 模式不依赖应用的代理设置——它是在网络层拦截所有 IP 包,因此对应用透明。
2.3 几种代理模式对比
| 模式 | 原理 | 覆盖范围 | 对应用透明 | 配置复杂度 | 适用场景 |
|---|---|---|---|---|---|
| 系统代理 | 设置 HTTP_PROXY 等环境变量 | 遵守系统代理 API 的应用 | 否 | 低 | 浏览器、curl 等 |
| TUN 模式 | 虚拟网卡 + 路由表劫持 | 所有 IP 流量 | 是 | 中 | Git、Docker、终端全代理 |
| TUN + Fake-IP | TUN 拦截 DNS 请求,Clash 返回假 IP,根据假 IP 反查域名 | TUN 模式 + DNS 本地加速 | 是 | 中 | 需要域名规则匹配、高 DNS 延迟场景 |
| 透明代理(Redirect) | iptables REDIRECT 将流量转到代理端口 | 所有 TCP 连接 | 是 | 高 | 网关级代理(路由器) |
TUN 模式可以替代所有工具的单独代理配置——它走的是路由层面,应用完全无感。代价是系统路由被修改,需要确保规则准确,否则可能导致内网流量也被劫持。
2.4 问题:TUN 下 DNS 为什么慢
TUN 模式下,每个新连接的第一步是 DNS 解析——应用需要知道 github.com 的 IP 才能发起 TCP 连接。
| |
DNS 请求本身是 UDP 包,大小不到 100 字节,但因为走了代理链路(Clash→代理服务器→公共 DNS),延迟通常在 100-500ms。每个新域名都要等这一下,体感就是"打开网页卡一下才加载"。
2.5 尝试:缓存真实 IP 行不行?
直观想法:Clash 把解析到的真实 IP 缓存下来,下次同一个域名直接返回缓存的 IP,不就快了吗?
不行,两个致命问题:
问题一:CDN 域名对应海量 IP,且频繁变动。
| |
这些 IP 的变化频率是分钟级。缓存意味着要维护一套 TTL、刷新、淘汰机制——复杂度和延迟不比直接走代理低。
问题二:更致命的——丢掉域名后无法精准匹配规则。
Clash 的规则核心是域名维度(DOMAIN-SUFFIX、DOMAIN-KEYWORD)。如果 DNS 返回的是真实 IP,当应用后续向这个 IP 发包时,TUN 交给 Clash 的就只是一个裸 IP 包——没有域名信息。
| |
缓存真实 IP 等于在 DNS 这一步丢弃了域名——而域名正是后续规则匹配最需要的信息。这就是为什么必须引入 Fake-IP。
2.6 方案:Fake-IP——把域名编码进 IP 里
既然问题根源是"IP 包阶段丢失了域名",Fake-IP 的思路就是把域名信息编码回 IP 包里——生成一个假的 IP,建立 假 IP ↔ 域名 的映射,让 Clash 从假 IP 反查出域名。
工作流程:
| |
与普通 TUN 的对比:
| 普通 TUN | TUN + Fake-IP | |
|---|---|---|
| DNS 延迟 | 100-500ms(走代理链路) | ~0ms(本地返回) |
| IP 包阶段 | 只有 IP,无域名 → 只能 IP 规则 | 反查得域名 → 可继续用域名规则 |
| 适用场景 | 规则以 IP-CIDR 为主时够用 | 规则以域名为主时必备 |
映射关系谁维护: Clash 进程在内存中维护一张哈希表 map[假IP]域名。写入:处理 DNS 请求时。读取:收到 TUN 设备的 IP 包时。进程退出即消失,重启后重建。
为什么不能脱离 TUN: Fake-IP 需要 TUN 同时拦截两个点——① DNS 请求(返回假 IP)、② 后续 IP 包(根据假 IP 反查域名)。没有 TUN,一个都拦不到。
2.7 正确性:如何保证只给需要代理的域名返假 IP?
这里有一个关键约束:Fake-IP 不能对所有 DNS 都返回假 IP。否则内网域名(git.service.rd)也拿到假 IP,应用连到假 IP 上,Clash 反查后发现规则是 DIRECT——但此时已经晚了一步,因为应用已经向假 IP 发起连接了。
Clash 的做法:在返回假 IP 之前,先跑规则匹配。
| |
只有命中代理规则的域名才进 Fake-IP 体系。内网域名命中 DIRECT → 正常 DNS 解析 → 拿到真实 IP → 直连,整个过程与 Fake-IP 无关。
规则配置示例:
| |
极端错误:如果 GEOIP,CN,DIRECT 写在域名规则之前,且 github.com 恰好解析到国内 CDN 节点,则 GitHub 被错误直连。解决:域名规则永远放在 IP 规则之前。
2.8 假 IP 从哪来,会冲突吗?
Clash 从 RFC 2544 保留的基准测试网段 198.18.0.0/15 中分配。这个 /15 提供 198.18.0.0 ~ 198.19.255.255 约 13 万个地址,专用于网络设备基准测试,不分配给任何公网或内网。
分配方式:每个新域名按递增序号分配——github.com → 198.18.0.1,google.com → 198.18.0.2,以此类推。重启清零重新分配。
| 网段 | 冲突可能 | 原因 |
|---|---|---|
10.0.0.0/8 | 不冲突 | 不在同一网段 |
172.16.0.0/12 | 不冲突 | 不在同一网段 |
192.168.0.0/16 | 不冲突 | 不在同一网段 |
198.18.0.0/15 | 极罕见 | RFC 保留段,全球无 ISP/企业生产使用 |
极端情况可切到 198.51.100.0/24(RFC 5737 文档/测试保留段)。
3. 各工具代理配置
3.1 Git
需求:GitHub 走代理,内网 Git 仓库直连。
按域名配置(推荐):
| |
这样只有 GitHub 走代理,其他域名直连,无需 no_proxy。
环境变量方式:
| |
仓库级别禁用代理:
| |
3.2 Docker Daemon
Docker daemon 是 systemd 服务,代理必须配置在 systemd unit file 中:
| |
验证:
| |
Docker daemon 代理影响的是
docker pull(daemon 从 registry 拉取镜像),不影响容器内部网络。容器内部需要单独配置代理或者宿主机开 TUN 模式。
3.3 容器内代理
构建镜像时如果需要走代理(如 apt install):
| |
| |
3.4 APT
| |
3.5 Minikube:国内镜像加速
无需代理,直接用国内 registry mirror:
| |
本质:Docker daemon 拉取镜像时先尝试 mirror 地址,失败才回退到原始 registry。比代理方案更稳定,因为国内 mirror 网络链路更短。
4. 故障排查
4.1 代理不生效
| |
4.2 内网也走了代理
常见原因:no_proxy 格式不对。
| |
4.3 开了 TUN 之后内网不通
TUN 模式劫持了所有流量。需要在 Clash 规则中排除内网网段:
| |
5. 总结
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 浏览器访问 GitHub | 系统代理 + SwitchyOmega | 最轻量 |
| Git clone GitHub | git config http.https://github.com.proxy | 按域名配置,内网不受影响 |
| VS Code / JetBrains 全代理 | TUN 模式 | 终端、插件、Git 一次性覆盖 |
| Docker pull gcr.io | daemon proxy 或 minikube registry mirror | daemon 层面配置 |
| CI/CD 构建 | --build-arg 传代理 | 不写入镜像,构建完即失效 |
| 全局开发环境 | TUN 模式 + 内网网段 DIRECT 规则 | 一劳永逸,对应用透明 |
选择代理方案的决策树:
| |