本文目录
docker pull、WSL 命令和容器请求来自不同位置
Docker 与 WSL2 要走 Windows 上的 Clash,不能只在一个终端里写代理。docker pull、WSL 里的 apt、镜像构建中的 RUN 和启动后的容器,分别由不同组件发出请求;哪一步报错,就配置哪一层。
Windows 上的 Clash 监听 127.0.0.1,只保证 Windows 本机能访问。WSL2 默认运行在 NAT 虚拟网络里,容器还有自己的网络命名空间;它们看到的 127.0.0.1 通常是自己,不是宿主机。
Docker 拉镜像、docker build 里的下载、运行中容器访问外网,也由不同组件发起。只在 WSL shell 里 export HTTP_PROXY,未必能让 Docker Desktop 的镜像拉取走代理。
报错发生在哪一层
| 失败动作 | 真正发起请求的组件 |
|---|---|
| curl / apt / git 在 WSL 里超时 | WSL 发行版中的进程 |
| docker pull 超时 | Docker Desktop 或 Docker Engine 守护进程 |
| RUN apt-get 在 build 时超时 | BuildKit / 构建容器 |
| 启动后的应用请求失败 | 运行中的容器 |
- Windows 上的 Clash监听局域网可达的 mixed-port
- WSL2使用宿主机地址访问该端口
- Docker 构建显式接收 HTTP_PROXY 和 HTTPS_PROXY
- 容器内工具再处理 Git、npm 或包管理器
127.0.0.1 在每一层都指向自己。代理地址必须填写上一层真实可达的宿主机地址。
宿主代理端口要能被虚拟网络访问
先在 Clash 查看实际的 HTTP 或 mixed-port,常见示例是 7890,但你的客户端可能不同。WSL 使用宿主 IP 访问时,这个连接会被当作局域网连接,客户端需要允许 LAN 访问,并监听 WSL 能到达的地址。
允许 LAN 会扩大端口可达范围。只在可信的家庭或单位私有网络使用,并让 Windows 防火墙限制来源;不要把无认证代理暴露到公共 Wi-Fi 或公网。完成测试后若不再需要,可以关闭 LAN 访问。
WSL 默认 NAT 用宿主 IP,镜像网络可直接试 127.0.0.1
默认 NAT 模式下,可以在 WSL 读取默认路由的下一跳,它通常就是 Windows 宿主在 WSL 虚拟网络里的地址。Windows 11 22H2 及后续版本启用 mirrored networking 后,WSL 可以直接通过 127.0.0.1 访问 Windows 服务。
HOST_IP=$(ip route show | grep -i default | awk '{ print $3 }')
CLASH_PORT=7890
echo "Windows host: $HOST_IP"
curl -I -x "http://${HOST_IP}:${CLASH_PORT}" https://example.com这条 curl 得到 HTTP 响应后,才有必要设置 WSL 环境变量。若代理端口直接返回 Connection refused,问题在 Clash 监听、允许 LAN 或防火墙;若端口可达但外部请求 timeout,再检查节点和规则。
端口可达后,再给 WSL 命令行设置环境变量
HOST_IP=$(ip route show | grep -i default | awk '{ print $3 }')
CLASH_PORT=7890
export HTTP_PROXY="http://${HOST_IP}:${CLASH_PORT}"
export HTTPS_PROXY="http://${HOST_IP}:${CLASH_PORT}"
export NO_PROXY="localhost,127.0.0.1,::1"
curl -I https://example.com临时变量关闭终端就会消失,适合排障。用 apt、git 或 curl 重做同一个请求,确认成功后,再按 shell 类型写进自己的启动文件。
Windows 支持的 WSL 版本也可以在 .wslconfig 使用 autoProxy=true,让 WSL 导入 Windows 的 HTTP 代理信息。启用后要重启 WSL,并检查实际变量值。
NO_PROXY 应包含只在 WSL 内部提供的服务,避免访问 localhost 时绕到 Windows 代理。公司内部域名和私有网段是否加入,要按实际网络决定。
docker pull 失败,要到 Docker Desktop 的代理设置
Docker Desktop 拉取镜像和 WSL shell 命令由不同进程发起。打开 Docker Desktop 的 Settings,在 Resources / Proxies(不同版本标签可能略有变化)里填写宿主可用的 HTTP、HTTPS 代理,并应用设置。
Docker 官方文档明确说明,Desktop 不读取 daemon.json 里的守护进程代理配置。不要因为 WSL 终端已经能访问,就跳过 Docker Desktop 自己的代理设置。
若使用的是独立 Linux Docker Engine,而不是 Docker Desktop,才按 Engine 文档在 daemon.json 或 systemd 环境中设置守护进程代理,并重启 Docker 服务。先确认自己运行的形态,避免改了一个根本不被读取的文件。
WSL curl 成功,docker pull 仍 timeout
检查 Docker Desktop 的 Proxies 设置和重启后的状态。
Docker Desktop 改 daemon.json 没效果
移到 Desktop 图形设置;该产品会忽略 daemon proxy 配置。
原生 Linux Engine 拉取失败
查看 daemon 的代理环境与服务日志,而不是 Windows 系统代理。
镜像能拉下来,构建步骤和运行容器仍可能没代理
Docker 的客户端配置可以为新容器和构建自动注入代理环境,也可以在单次命令里显式传入。构建时用 --build-arg,运行时用 --env;不要在 Dockerfile 里用 ENV 固化带凭据的代理地址,镜像历史和配置可能把它留下。
CLASH_PROXY=http://host.docker.internal:7890
docker build \
--build-arg HTTP_PROXY="$CLASH_PROXY" \
--build-arg HTTPS_PROXY="$CLASH_PROXY" \
-t demo-app .
docker run --rm \
--env HTTP_PROXY="$CLASH_PROXY" \
--env HTTPS_PROXY="$CLASH_PROXY" \
--env NO_PROXY="localhost,127.0.0.1" \
demo-appDocker Desktop 通常提供 host.docker.internal 指向宿主机。原生 Linux Engine 是否可用取决于环境,需要用明确的宿主网关或额外 host-gateway 配置。命令执行前,用容器内的 curl 或应用日志验证这个主机名和端口确实可达。
NO_PROXY 写漏了,容器之间的请求也会绕远
数据库名、Compose 服务名、localhost 和内部网段通常不该交给外部代理。把实际内部域名加入 NO_PROXY,能避免应用访问 db:5432、redis:6379 时先去 Windows 兜一圈。不同工具对通配符和 CIDR 的支持不完全相同,配置后要在目标进程里打印变量并做实际请求。
代理地址若含用户名或密码,不要写进公开的 compose.yaml、Dockerfile 或镜像。使用本地环境文件或项目的 secret 管理方式,并确保日志不会把完整 URL 打出来。
按实际使用完成四次验证
- WSL 中 curl 通过 Windows Clash 得到响应
- docker pull 可以拉取一个小镜像
- docker build 的网络步骤不再超时
- 运行容器既能访问外网,也能直连内部服务
四项结果可以分别对应到 WSL、Docker 引擎、构建过程和运行容器。哪一项仍失败,就回到那一层的设置,不必重新改已经通过的其他三层。
