Docker 拉取镜像、安装依赖或访问 GitHub 超时,往往不是节点本身失效,而是请求根本没有进入 Clash 的代理链路。Docker 容器拥有独立的网络命名空间,Docker daemon 拉取镜像时也可能由后台服务发起,因此「宿主机浏览器可以访问」并不代表容器和 Docker Hub 同样可以访问。本文从流量路径与容器网络原理入手,讲清 Clash 透明代理的工作方式,并给出适用于 Linux 宿主机、Docker 容器和 CI 开发环境的完整配置、规则分流与排障方案。

透明代理与 Docker 流量路径

普通 Clash 客户端通常提供 HTTP、SOCKS5 或混合端口,例如 7890。浏览器只要配置代理地址,就能将请求发送到这些端口。但 Docker 容器中的程序未必读取 HTTP_PROXY 环境变量,也未必支持 SOCKS5;Docker daemon 更是由 systemd 单独启动,和当前终端的环境变量没有直接关系。

透明代理的思路是:应用无需知道代理端口,宿主机通过 TUN、重定向端口或防火墙规则拦截出站连接,再交给 Clash 根据域名和 IP 规则转发。一个典型的请求路径如下:

  1. 容器内的 gitcurl 或包管理器发起连接。
  2. 数据包经由 Docker bridge 离开容器网络命名空间,进入宿主机。
  3. 宿主机的 nftables 或 iptables 规则识别目标流量,并将其重定向到 Clash 的透明入口。
  4. Clash 根据域名、IP-CIDR、进程或规则集选择代理节点。
  5. 代理连接建立后,流量从节点出口访问 GitHub、Docker Hub 或其他目标服务。

需要特别区分三类流量:容器内业务请求、Docker daemon 的镜像请求,以及宿主机自身请求。三者可能使用不同的网络命名空间和用户身份。如果只配置了容器环境变量,通常不能解决 Docker daemon 的拉取问题;如果只给 daemon 配置代理,也不能自动代理容器中运行的构建脚本。

先判断请求是谁发出的:执行 docker pull 时,访问镜像仓库的是 Docker daemon;执行 docker run 后,访问 GitHub 的可能是容器内进程;执行 docker build 时,下载依赖的请求通常来自构建容器。确定发起者后再选择配置位置,排障效率会高很多。

选择 Clash 透明代理模式

在 Linux 宿主机上,Mihomo 通常可以通过 TUN 模式接管系统流量,也可以通过 redir-host、tproxy 等传统方式处理 TCP 或 UDP 连接。Docker 开发环境优先推荐 TUN 模式,因为它对应用的侵入较小,不需要为每个命令单独设置代理变量;如果设备是路由器或服务器,则应根据现有防火墙体系选择 TProxy 或显式 HTTP 代理。

方案适用场景优点注意事项
tunLinux 开发机、虚拟机、单台服务器接管范围广,应用通常无需改配置需要内核能力与路由权限,避免回环
redir-host仅处理 TCP 的简单环境兼容性较好,配置容易理解UDP、DNS 和部分新协议可能不被接管
tproxy网关、旁路由、需要完整透明转发的场景可保留原始目标信息,适合复杂分流iptables/nftables 规则和策略路由更复杂
显式代理CI、单个服务或不方便改防火墙的主机边界清楚,容易审计与回滚每个服务都必须正确设置代理变量

下面是一份适合 Mihomo 的 TUN 基础配置。auto-route 负责写入路由,auto-detect-interface 避免多网卡环境下选错出口,strict-route 可以减少 DNS 和连接绕过 TUN 的情况。不同版本字段支持情况可能略有差异,生产环境应先用当前客户端的配置校验功能检查。

Mihomo TUN 基础配置
mixed-port: 7890
allow-lan: true
mode: rule

tun:
  enable: true
  stack: mixed
  device: mihomo
  auto-route: true
  auto-detect-interface: true
  strict-route: true

dns:
  enable: true
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  nameserver:
    - 223.5.5.5
    - 119.29.29.29
  fallback:
    - tls://1.1.1.1:853
    - tls://8.8.8.8:853

Docker bridge 常见网段是 172.17.0.0/16,但实际环境可能使用 172.18.0.0/16 或自定义网段。不要机械复制网段到配置中,应先执行 docker network inspect bridge 查看 Subnet。如果 TUN 已经接管宿主机全部流量,通常不需要手动把每个 Docker 网段加入规则;若使用 TProxy 或自定义 nftables,则必须明确放行并转发这些网段。

为 GitHub 与 Docker Hub 设置规则分流

透明代理能否稳定工作,关键不只是「把流量送进 Clash」,还要保证域名解析和规则匹配正确。GitHub 相关请求不只有 github.com,还可能访问 api.github.comraw.githubusercontent.comobjects.githubusercontent.comgithubusercontent.com 以及用于下载 Release 的 CDN。Docker Hub 同样涉及认证域名、镜像存储域名和 CDN,单独添加 docker.io 往往不够。

GitHub 与 Docker Hub 分流规则
proxy-groups:
  - name: 开发服务
    type: select
    proxies:
      - 自动选择
      - DIRECT

  - name: 自动选择
    type: url-test
    use:
      - 订阅节点
    url: https://www.gstatic.com/generate_204
    interval: 300

rules:
  - DOMAIN-SUFFIX,github.com,开发服务
  - DOMAIN-SUFFIX,githubusercontent.com,开发服务
  - DOMAIN-SUFFIX,githubassets.com,开发服务
  - DOMAIN-SUFFIX,docker.com,开发服务
  - DOMAIN-SUFFIX,docker.io,开发服务
  - DOMAIN,registry-1.docker.io,开发服务
  - DOMAIN,auth.docker.io,开发服务
  - DOMAIN,production.cloudflare.docker.com,开发服务
  - MATCH,DIRECT

规则顺序非常重要。更具体的域名规则应放在前面,兜底规则 MATCH 必须放在最后。如果团队使用多个出口,可以将 GitHub 和 Docker Hub 拆成两个策略组:代码托管走延迟较低的节点,镜像下载走带宽更高的节点。对于国内镜像源,则可以在代理规则之前添加对应的直连规则,避免所有镜像请求都绕行代理。

Docker Hub 的实际镜像层下载地址可能随区域和仓库变化。遇到认证成功但下载 layer 失败时,不要只检查 registry-1.docker.io,应在 Clash Dashboard 的连接页面查看真实目标域名,再补充精确规则。这样比盲目添加大量关键词规则更安全,也能避免把无关的 Docker 服务误送到代理。

配置 Docker daemon 与容器代理

如果目标是解决 docker pulldocker build 拉取基础镜像超时,最稳定的方式通常是为 Docker daemon 配置显式代理。假设 Clash 的 HTTP 混合端口监听在宿主机 127.0.0.1:7890,Docker daemon 运行在宿主机上时可以使用该地址;如果 daemon 位于另一个容器或远程主机中,则不能使用它自己的 127.0.0.1,必须改为 Clash 所在主机的可达地址。

为 Docker daemon 设置代理
# 创建 systemd drop-in 目录
sudo mkdir -p /etc/systemd/system/docker.service.d

# 写入代理配置,地址按实际 Clash 监听位置修改
sudo tee /etc/systemd/system/docker.service.d/proxy.conf > /dev/null <<'EOF'
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1,::1,172.17.0.0/16,172.18.0.0/16"
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show --property=Environment docker

NO_PROXY 应包含本地地址、Docker bridge 网段、公司内网域名和私有镜像仓库地址,否则内部服务可能被错误地发送到外部代理。修改 daemon 配置后,已有容器不会自动继承新的环境变量;它主要影响 daemon 自身和由 daemon 发起的镜像操作。

如果构建过程中的 aptnpmpipgo 请求仍然失败,需要在构建阶段传入代理。Dockerfile 中不建议硬编码真实代理地址,可以用构建参数或 Compose 的环境变量注入:

Docker Compose 注入构建与运行代理
services:
  builder:
    build:
      context: .
      args:
        HTTP_PROXY: ${HTTP_PROXY}
        HTTPS_PROXY: ${HTTPS_PROXY}
        NO_PROXY: ${NO_PROXY}
    environment:
      HTTP_PROXY: ${HTTP_PROXY}
      HTTPS_PROXY: ${HTTPS_PROXY}
      NO_PROXY: ${NO_PROXY}

在 Linux 上,容器访问宿主机的代理端口不能直接把 127.0.0.1 写进容器环境变量,因为那代表容器自身。可以使用宿主机在 Docker bridge 上的地址,或在 Compose 中声明 host.docker.internal 映射。若 Clash 只监听回环地址,容器无法访问它;此时应让 Clash 监听宿主机可达地址,并配合防火墙限制来源,避免把代理端口暴露到公网。

生产环境排障与安全加固

建议按照「DNS、连通性、代理入口、规则命中、目标服务」的顺序排查,不要一开始就反复更换节点。首先在宿主机执行 curl -I https://github.com,确认宿主机网络;然后进入容器测试:

分层验证容器网络
# 查看 Docker 网络与网段
docker network inspect bridge

# 使用临时容器测试 DNS 与 HTTPS
docker run --rm curlimages/curl:latest -I -v https://github.com

# 测试 Docker Hub 认证接口
docker run --rm curlimages/curl:latest -I https://auth.docker.io/token

# 查看 daemon 日志
sudo journalctl -u docker -n 100 --no-pager

如果容器提示无法解析域名,优先检查 Docker 的 DNS 配置、Clash 的 DNS 监听和 fake-ip 网段是否冲突;如果域名能解析但 TCP 连接超时,再检查 TUN 是否接管了 Docker 网段,以及宿主机防火墙是否允许转发。如果宿主机可用、容器不可用,问题通常位于 bridge、路由或代理监听地址,而不是节点本身。

在 Clash Dashboard 的连接列表中,重点观察以下信息:目标域名是否出现、命中的规则是否为预期策略组、连接是否在握手阶段失败、是否有重复连接反复重试。对于 Docker Hub,若只看到认证域名而看不到 layer 下载域名,说明规则覆盖不完整;对于 GitHub,若 github.com 可访问但 Release 下载失败,通常需要继续检查 objects.githubusercontent.com 或实际 CDN 域名。

不要直接暴露代理端口:allow-lan: true 只表示允许局域网访问,并不等于安全。生产服务器应使用防火墙限制 7890 等端口的来源,设置 Clash API 的 secret,并避免将 external-controller 绑定到公网地址。代理端口一旦被扫描利用,可能造成流量盗用和出口 IP 风险。

最终配置应尽量做到可回滚:先保存当前 Clash 配置和 Docker systemd drop-in 文件,再一次只修改一个变量;使用 docker info 验证 daemon 代理是否生效,使用临时容器验证应用代理,使用 Dashboard 验证规则命中。确认 GitHub API、Raw 文件、Docker Hub 认证和镜像 layer 下载都正常后,再把配置推广到 CI 或生产主机。这样既能解决开发环境中的超时问题,也能避免透明代理规则过宽造成内网流量误代理。

立即开始

用 Clash 掌控你的流量

支持 Windows、macOS、Linux、Android 与 iOS,灵活规则,开箱即用。

免费下载 查看设置指南 →