前言:为什么 Docker pull 会超时?
使用 Clash 后,浏览器可以正常打开海外网站,并不代表 Docker 一定能够顺利拉取 Docker Hub 镜像。很多用户执行 docker pull nginx、docker pull ubuntu 或 docker compose up 时,仍然会遇到 i/o timeout、Client.Timeout exceeded、context deadline exceeded、TLS handshake timeout 等错误。
这类问题的关键通常不在 Docker Hub 本身,而在于 Docker CLI 与 Docker daemon 的运行方式。Clash 的系统代理主要面向浏览器和支持 HTTP 代理的普通应用,而 Docker daemon 可能作为独立后台服务运行,既不会自动读取桌面客户端的代理设置,也不会主动使用 Clash 的规则。即使 Clash 已经开启,Docker 仍可能直接连接 registry-1.docker.io、认证服务和镜像 CDN,最终因为网络不可达而超时。
本文将按照“先确认节点,再确认 Clash,再确认 Docker 代理,最后检查规则和 DNS”的顺序排查。你不需要一开始就修改大量配置,只要每一步都验证结果,就能准确判断问题究竟发生在节点、客户端、系统代理,还是 Docker 服务本身。
排查目标
让 Docker 的镜像请求明确进入 Clash,并通过稳定节点访问 Docker Hub;同时保留国内镜像仓库直连,避免所有镜像流量都经过代理。
1先看报错,判断故障位置
不要看到超时就立即更换配置。Docker 的报错信息虽然比较简短,但通常可以帮助我们缩小范围。建议先完整复制终端中的错误内容,尤其要注意其中出现的域名、端口和错误类型。
| 典型现象 | 常见原因 | 优先检查项目 |
|---|---|---|
连接 registry-1.docker.io 超时 |
Docker 未使用 Clash,或规则没有命中 | Docker daemon 代理、Clash 日志 |
TLS handshake timeout |
节点丢包、延迟过高或 HTTPS 建连不稳定 | 更换节点、测试代理端口 |
no basic auth credentials |
已经连接到仓库,但认证流程失败 | 登录状态、认证域名分流 |
manifest unknown 或 pull access denied |
镜像名称、标签错误,或仓库需要权限 | 镜像名、tag 与账号权限 |
| 浏览器正常,Docker 始终超时 | 系统代理只作用于浏览器,未作用于 daemon | systemd、Docker Desktop 代理设置 |
如果错误明确显示为镜像不存在或权限不足,就不要继续反复切换 Clash 节点。先确认镜像名称是否正确,例如官方镜像通常可以使用 nginx:latest,而私有仓库则需要先执行 docker login。只有当错误属于连接、解析或 TLS 超时,才应该重点检查代理链路。
2确认 Clash 节点和代理端口正常
在修改 Docker 之前,先验证 Clash 自己是否能够访问 Docker Hub。打开 Clash Verge、Clash Verge Rev、Clash for Windows 或其他 Mihomo 客户端,确认订阅已经更新、代理模式处于 Rule 或 Global,并且当前策略组选择了可用节点。
桌面客户端常见的混合端口是 7890,但不同配置可能使用其他端口;Clash Verge Rev 和 Mihomo 配置也可能分别设置 mixed-port、port 或 socks-port。不要盲目照抄端口,应该在客户端设置页或配置文件中确认实际监听地址。
用命令测试 HTTP 代理
在 Windows PowerShell、macOS Terminal 或 Linux Shell 中执行以下命令,把端口替换为你的 Clash 混合端口:
如果能够返回 HTTP/1.1 401 Unauthorized 或类似响应,反而说明网络连接已经建立;Docker Hub 的 Registry 接口在未携带凭据时返回 401 是正常现象。若命令直接报连接被拒绝,说明端口写错、Clash 未启动,或者客户端只监听了其他地址。若连接很慢并最终超时,则优先更换节点,而不是先修改 Docker 配置。
查看 Clash 日志是否出现请求
执行测试命令的同时打开 Clash 日志,搜索 docker.io、auth.docker.io、registry-1.docker.io 等关键词。如果日志完全没有相关请求,说明请求没有进入 Clash;如果日志出现请求但状态为 timeout、connection reset 或持续重试,则需要检查节点质量、DNS 解析和远端服务连通性。
判断节点质量的小技巧
不要只看延迟数值。Docker 拉取镜像包含认证、清单查询和多个分层下载,节点还需要具备稳定带宽和较低丢包率。一个延迟 80 毫秒但频繁断流的节点,通常不如延迟 180 毫秒但连接稳定的节点。
3Docker Desktop:单独设置代理
Windows 和 macOS 用户大多使用 Docker Desktop。它包含自己的虚拟化环境与后台服务,不能简单地认为系统代理一开,Docker Desktop 就会自动继承。最稳妥的方式是在 Docker Desktop 的设置中显式填写代理。
- 打开 Docker Desktop,进入 Settings,找到 Resources 或 Proxies 相关页面。不同版本的菜单名称可能略有差异。
- 启用手动代理配置,HTTP Proxy 和 HTTPS Proxy 都填写 Clash 的混合代理地址,例如
http://host.docker.internal:7890或http://127.0.0.1:7890。 - 点击保存并重启 Docker Desktop,让 daemon 重新加载代理环境。
- 重启后先执行
docker info,确认 Docker 服务已经正常运行,再测试一个体积较小的镜像。
地址选择取决于 Docker Desktop 的运行环境。Windows 和 macOS 上,host.docker.internal 通常可以让容器或虚拟机访问宿主机;Linux 原生 Docker 则通常使用 127.0.0.1,但 systemd 服务与桌面用户的网络命名空间不同,具体要结合服务配置验证。
不要混淆端口类型
Docker 的 HTTP/HTTPS 代理应优先填写 Clash 的 HTTP 混合端口,而不是把 SOCKS5 端口直接填入 HTTP Proxy。若只有 SOCKS5 端口,请确认 Docker Desktop 当前版本是否支持 SOCKS5,或在 Clash 中启用兼容的 mixed-port。
4Linux:为 Docker daemon 配置 systemd 代理
Linux 上最常见的情况是:终端里设置了 export http_proxy=...,但 Docker 服务仍然无法拉取镜像。原因是 docker pull 的实际请求由后台运行的 Docker daemon 发出,当前 Shell 的环境变量不会自动传递给 systemd 服务。
可以为 Docker 创建 systemd drop-in 配置。下面示例假设 Clash 与 Docker 位于同一台机器,并监听本机 7890 端口:
最后一条命令用于确认环境变量已经注入 Docker 服务。如果能看到 HTTP_PROXY 和 HTTPS_PROXY,再执行:
如果 Clash 运行在另一台主机,不能继续使用 127.0.0.1,而要填写 Docker 主机能够访问的局域网地址,例如 http://192.168.1.20:7890。同时,Clash 的监听地址需要允许局域网访问,并且防火墙必须放行对应端口。为了安全,不建议把代理端口直接暴露到公网。
处理 Docker Compose 与容器内代理
daemon 代理只负责拉取镜像和访问 Registry,不等于容器内部应用也自动拥有代理。若你的构建步骤需要下载 GitHub、npm 或 PyPI 资源,还要在构建参数或 Compose 环境变量中单独配置:
对于不需要代理的内网、数据库和本机服务,应加入 NO_PROXY,例如 localhost,127.0.0.1,.internal,192.168.0.0/16。这样可以避免内部请求绕行 Clash,也能减少代理规则误判。
5检查规则命中、DNS 与 TUN 模式
Docker Hub 不只有一个域名。拉取流程可能依次访问 Registry、认证服务和内容分发网络。如果规则只写了一个域名,或者策略组指向了不可用节点,就会出现“能登录但拉取失败”或“能获取 manifest 但下载 layer 超时”的情况。
可以在自定义规则或 Merge 配置中加入一组明确的规则,并将它们放在通用 GEOIP 或 MATCH 规则之前:
其中 Docker 应替换成你实际存在的策略组名称。规则名称并不会自动创建策略组,如果配置中没有同名组,Clash 可能报配置错误,或者无法按预期分流。添加规则后重新加载配置,并在连接日志中确认这些域名是否确实走到了目标策略组。
DNS 解析异常怎么处理?
当系统 DNS 返回了不可达地址、被污染的结果,或者 Docker daemon 无法解析域名时,代理本身再稳定也无法建立连接。可以先分别测试:
如果直连解析失败而通过 Clash 代理访问成功,说明应重点检查 Clash DNS 设置。Mihomo 通常可以使用 fake-ip 或 redir-host 模式;选择哪一种要看系统兼容性。遇到 Docker、虚拟机或局域网设备解析异常时,可以暂时切换模式进行对比,不建议一次修改多个 DNS 参数后无法判断究竟是哪项生效。
何时需要开启 TUN?
如果 Docker daemon 无法使用 HTTP 代理,或者某些请求明显绕过了 Clash,可以考虑在 Clash Verge Rev、Mihomo 客户端中开启 TUN 模式。TUN 会在系统层接管更多 TCP/UDP 流量,适合处理不遵循系统代理的程序。不过它需要系统权限,并可能与其他 VPN、虚拟网卡、企业安全软件发生冲突。
推荐的验证顺序
先用显式 HTTP 代理验证 Docker,再尝试 TUN 模式。TUN 不是所有问题的万能解决方案;如果节点本身无法访问 Docker Hub,开启 TUN 只会让故障表现更加复杂。
6最后验证:用最小测试闭环定位
配置完成后,不要直接拉取几个 GB 的大型镜像。建议按从小到大的顺序完成验证,这样既节省时间,也能知道哪一层已经恢复正常。
- 验证 Clash 端口:使用
curl -x请求https://registry-1.docker.io/v2/,确认代理端口可以建立连接。 - 验证 Docker daemon:执行
docker info,确认客户端能够连接 Docker 服务,且服务没有持续重启。 - 验证公共镜像:执行
docker pull hello-world,观察认证、manifest 和 layer 下载是否都成功。 - 验证指定标签:使用明确版本,例如
docker pull nginx:1.27,排除 latest 标签变更造成的误判。 - 验证构建网络:如果只有
docker build失败,检查 Dockerfile 中的包管理器是否需要额外代理,而不是继续修改 Registry 代理。
若拉取过程中速度忽快忽慢,可以在 Clash 连接日志中观察是否频繁切换节点。自动选择策略组可能依据延迟测试更换节点,但镜像分层下载期间切换出口会造成连接中断。排查阶段建议手动固定一个稳定节点,确认问题解决后再考虑使用 url-test 或负载均衡策略。
- Clash 客户端正在运行,订阅和节点没有过期。
- HTTP 或 mixed-port 端口与实际配置一致。
- curl 通过代理能够访问 Registry,并在日志中留下请求记录。
- Docker Desktop 已填写代理,或 Linux daemon 已加载 systemd drop-in。
docker.io、auth.docker.io和 CDN 域名命中了正确策略组。- 没有重复运行 VPN、代理软件或冲突的 TUN 网卡。
- 私有仓库已登录,镜像名称和 tag 拼写正确。
常见问题解答
Docker pull 一定要开启 TUN 模式吗?
不一定。只要 Docker daemon 能够正确使用 Clash 的 HTTP 代理,就可以正常拉取镜像。TUN 更适合无法配置代理、请求经常绕过系统代理,或需要接管更多底层流量的场景。优先使用显式代理更容易验证,也更方便后续排错。
为什么浏览器能打开 Docker Hub,Docker 却显示超时?
浏览器通常会读取系统代理或浏览器扩展设置,而 Docker daemon 是独立服务,可能运行在虚拟机或 systemd 环境中。两者使用的网络路径并不相同,因此必须单独设置 Docker Desktop 代理,或为 Linux 的 Docker 服务配置 HTTP_PROXY 和 HTTPS_PROXY。
HTTP_PROXY 和 HTTPS_PROXY 应该填什么?
如果 Clash 提供 mixed-port,通常可以将两个变量都填写为同一个 HTTP 代理地址,例如 http://127.0.0.1:7890。端口必须以你的实际配置为准。除非 Docker 版本明确支持,否则不要把 socks5:// 地址直接当作 HTTPS Proxy 使用。
配置后仍然 TLS handshake timeout,该换什么?
先固定一个节点并测试稳定性,再检查 DNS 和规则命中。如果其他海外站点也出现 TLS 超时,问题更可能来自节点拥塞、丢包或出口限制;如果只有 Docker Hub 失败,则重点检查 Registry、认证域名和 CDN 域名是否都进入了正确策略组。
只要遵循“代理端口可用、Clash 日志有请求、daemon 明确继承代理、规则覆盖完整、节点保持稳定”的闭环,Docker Hub 拉取超时通常都能快速定位。完成排查后,建议保留一份可工作的 Docker 代理配置,并记录端口、策略组和 NO_PROXY 内容,方便系统升级或更换 Clash 客户端后恢复。