前言:为什么 Docker 容器总是访问超时?
在本机使用 Clash Verge、Clash Verge Rev 或 Mihomo 时,浏览器通常可以正常访问 Docker Hub、GitHub、npm Registry 和 PyPI,但同一台电脑上的 Docker 容器却频繁出现 i/o timeout、context deadline exceeded、connection reset 或镜像拉取速度极慢等问题。根本原因往往不是节点本身不可用,而是容器的网络数据流没有经过 Clash。
Clash 的系统代理主要服务于遵循 HTTP、HTTPS 或 SOCKS 代理设置的应用,Docker 容器、包管理器以及某些构建脚本却可能直接通过 Docker bridge 网卡访问外网。此时,浏览器走的是代理路径,容器走的是默认网关;两条路径使用了不同的 DNS、出口 IP 和防火墙策略,自然会产生“宿主机能访问、容器却超时”的现象。
本文的适用场景
本文以 Linux Docker 主机和 Mihomo/Clash.Meta 为例,介绍宿主机透明代理、Docker 网桥转发、DNS 防泄漏及规则分流。Windows 与 macOS 用户可以采用 Docker Desktop 的显式代理方案,或在宿主机启用支持 TUN 的 Clash 客户端后,再按容器环境调整地址。
配置之前建议先确认三件事:Clash 的代理端口是多少、Docker 网桥的网段是什么,以及容器访问宿主机时使用哪个地址。常见 HTTP 代理端口为 7890,透明代理端口为 7892,但实际值必须以客户端配置为准,不能直接照抄。
1先理解数据流与 DNS 路径
Docker 默认会创建名为 docker0 的网桥,例如 172.17.0.1/16。容器发送请求时,数据包通常经过以下路径:容器虚拟网卡、Docker 网桥、宿主机的 iptables/nftables 转发链、物理网卡,最后到达上游网关。如果没有透明代理规则,这些连接不会自动进入 Clash 的监听端口。
DNS 是另一个容易被忽略的环节。容器中的 /etc/resolv.conf 经常指向 Docker 内置 DNS 127.0.0.11,由 Docker 再转发到宿主机或运营商 DNS。即使 TCP 流量之后进入代理,域名解析仍可能已经失败、被污染,或者解析到不适合当前出口的地址。因此,排障时不能只测试 curl,还要分别检查解析结果和实际连接路径。
- 检查容器 DNS:执行
cat /etc/resolv.conf,确认是否使用 Docker 内置解析器。 - 检查默认路由:执行
ip route,确认默认网关通常指向 Docker 网桥地址。 - 检查宿主机端口:使用
ss -lntp | grep 7892,确认透明代理端口正在监听。 - 区分域名与 IP 问题:分别测试
getent hosts registry.npmjs.org和curl -I https://registry.npmjs.org。
不要把 127.0.0.1 写进容器配置
容器内的 127.0.0.1 指向容器自身,不是宿主机。若要访问宿主机上的 Clash,应使用 Docker 网桥网关,例如 172.17.0.1,或通过 host.docker.internal 映射宿主机地址。
2配置 Mihomo 透明代理与 DNS
透明代理的核心是让 Clash 在宿主机上监听一个能够接收转发流量的端口,然后由 iptables 或 nftables 将 Docker 网桥发出的 TCP 请求重定向到该端口。Mihomo 常见的配置方式是开启 Redir-Host、TProxy 或 mixed 监听器。对于只处理 TCP 的基础场景,redir-port 比较容易理解;如果需要同时接管 UDP、QUIC 或更复杂的流量,则应优先考虑 TProxy 或 TUN。
下面是一份适合改写到现有配置中的示例。节点和策略组部分没有列出,请将 PROXY 替换为你实际使用的策略组名称:
如果你的 Clash 客户端已经启用了 TUN 模式,通常不需要再为 Docker 单独写一套复杂的重定向规则。TUN 会创建虚拟网卡并接管系统路由,适合桌面开发环境;但在服务器上,iptables 或 nftables 方案更容易精确限制来源网段,也便于审计和回滚。
iptables 转发规则示例
假设 Docker 网桥为 docker0,网段为 172.17.0.0/16,Clash 的 Redir 端口为 7892。可以建立独立链,避免直接修改默认链导致后续难以维护:
注意转发权限与回环
请确认系统开启了 IPv4 转发,并且 Clash 进程有权限监听对应端口。不要把已经由 Clash 发出的流量再次重定向,否则可能形成代理回环,表现为 CPU 占用升高、连接不断重试或所有请求都超时。生产环境还应根据实际网段补充 OUTPUT、POSTROUTING 和 IPv6 规则。
3动手配置:让容器访问 Docker Hub 与包仓库
完成 Clash 配置后,建议先创建一个临时测试容器,不要立即修改所有业务服务。这样可以把 DNS、路由、代理规则分别验证,出现问题时也容易清理。
- 启动一个带网络工具的测试容器,并查看默认路由:
docker run --rm -it alpine:3.20 sh,然后执行ip route。 - 检查 DNS 解析:执行
nslookup registry.npmjs.org或getent hosts pypi.org。如果解析阶段就超时,应先修复 Docker DNS,而不是继续调整代理节点。 - 验证 HTTPS:执行
wget -S -O /dev/null https://registry.npmjs.org,观察是否能够完成 TLS 握手。 - 验证镜像仓库:在宿主机执行
docker pull alpine:latest,同时打开 Clash 日志,确认请求命中了 Docker 相关规则。 - 确认规则命中后,再对 npm、pip 和 GitHub Actions 使用同样方法测试,避免把单个站点的成功误认为所有域名都已正常。
如果不希望使用透明代理,也可以给单个容器配置显式代理。Docker Compose 示例中的 host-gateway 可以把宿主机地址映射为固定名称:
显式代理适合构建容器、CI 任务和少量开发服务,因为配置清晰、影响范围小;透明代理适合无法设置代理变量的二进制程序、系统包管理器或多个现有容器。两者不要在同一流量上重复套用,否则可能出现代理协议不匹配或请求循环。
推荐选择
个人开发机优先使用 TUN 或显式代理;单机 Linux 服务器可使用 Docker 网桥加 iptables;生产集群则建议在出口网关或专用 egress 节点统一处理代理,不要让每个业务容器自行维护节点配置。
4规则管理、日志排障与生产自动化
开发工具使用的域名数量会不断变化。Docker Hub 不只有 docker.io,还可能涉及认证服务、内容分发域名和镜像加速域名;GitHub 同样会使用 github.com、githubusercontent.com、ghcr.io 等不同域名。因此,规则应当集中管理,而不是散落在多份容器环境变量中。
- 规则顺序优先:自定义的 Docker、GitHub、npm 和 PyPI 规则应放在通用的
GEOIP、MATCH之前,否则可能被提前匹配为直连。 - 按用途拆分策略组:可建立
Dev-Registry、Git-Service和General-Proxy,分别选择稳定节点,避免一个节点故障影响所有开发流量。 - 避免过度使用 DOMAIN-KEYWORD:关键词规则虽然方便,但可能误匹配无关域名。优先使用
DOMAIN-SUFFIX,并定期检查命中日志。 - 控制 fake-ip 范围:某些企业内网域名、硬编码 IP 的程序或特殊许可证服务可能不兼容 fake-ip,应通过
fake-ip-filter或规则将其排除。
常见故障的定位顺序
- 容器无法解析域名:检查 Docker daemon 的 DNS 设置、宿主机防火墙和 Clash DNS 监听地址。
- 解析正常但 TLS 超时:检查透明代理端口是否监听 TCP,iptables 是否只匹配了正确的 Docker 网桥。
- 只有 HTTPS 失败:确认代理策略组可用,并检查 MTU、IPv6、SNI 与时间同步。容器时间错误也会导致 TLS 证书校验失败。
- 镜像能拉取但 npm 失败:检查是否配置了错误的
NO_PROXY,以及 npm 自身是否保存了旧代理:npm config get proxy。 - 重启后规则消失:将 iptables 规则保存到系统持久化服务,或使用 systemd、Ansible 等工具在网络和 Docker 服务启动后自动恢复。
生产环境不建议直接把订阅内容写入镜像,也不要在仓库中提交带有认证信息的代理 URL。可以使用 Docker secrets、环境变量注入和最小权限账户管理凭据。上线前还应记录规则变更、节点切换和异常连接数量,并设置健康检查,确认代理不可用时业务能够快速切换到备用出口或明确失败,而不是无限重试占满连接池。
最终检查清单
确认 Clash 端口监听正常、Docker 网桥网段准确、DNS 能稳定解析、规则命中预期策略组、iptables 没有回环,并分别测试 Docker Hub、GitHub、npm 与 PyPI。只有这些项目都通过,才能判断透明代理真正解决了开发工具超时问题。
通过“先确认数据流,再处理 DNS,最后添加转发规则”的顺序排障,通常比盲目更换节点有效得多。透明代理并不是把所有流量简单塞进 Clash,而是建立一条可观察、可分流、可回滚的网络路径;这也是它能够长期服务于本地开发和生产构建环境的关键。