跳到主要内容

首页 / 博客 / 部署实战

让 Docker 和 WSL2 用上宿主机的 Clash 代理

部署实战2026-06-141716 字约 4 分钟
让 Docker 和 WSL2 用上宿主机的 Clash 代理

宿主机上 Clash 跑得好好的,一进容器就全是超时。原因很简单:容器有自己的网络命名空间,127.0.0.1 指的是容器自己。

核心前提:开 allow-lan

不管哪种方案,第一步都一样——让 Clash 监听的地址从 127.0.0.1 变成 0.0.0.0

在 Clash Verge 里打开 允许局域网连接,或在配置里写:

allow-lan: true
bind-address: "*"
mixed-port: 7897

验证:

netstat -an | findstr 7897

看到 0.0.0.0:7897 才算成功。看到 127.0.0.1:7897 说明没开。

Docker:三个不同的场景

很多人踩坑是因为没分清这三件事其实需要分别配置。

三个场景,三套配置11. docker pull 拉镜像是 Docker daemon 在联网,要配 daemon 的代理22. docker build 构建时是构建容器在联网,要传 build-arg33. docker run 容器运行时是容器内进程在联网,要传环境变量
配了其中一个另外两个不会自动生效,这是最常见的困惑来源

场景一:docker pull 拉不动镜像

这是 Docker daemon 在联网,跟容器无关。

Docker Desktop(Windows / macOS): 设置 → Resources → Proxies → 打开 Manual proxy configuration,填:

HTTP:  http://127.0.0.1:7897
HTTPS: http://127.0.0.1:7897
Bypass: localhost,127.0.0.1,*.local

Docker Desktop 的 daemon 跑在虚拟机里但能访问宿主机 loopback,所以这里填 127.0.0.1 是对的。

Linux 上的 Docker(systemd)

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/proxy.conf > /dev/null <<'EOF'
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7897"
Environment="HTTPS_PROXY=http://127.0.0.1:7897"
Environment="NO_PROXY=localhost,127.0.0.1,::1,*.local,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

验证:

sudo systemctl show --property=Environment docker

场景二:docker build 时装依赖超时

构建过程发生在临时容器里,需要显式传入:

docker build \
  --build-arg HTTP_PROXY=http://host.docker.internal:7897 \
  --build-arg HTTPS_PROXY=http://host.docker.internal:7897 \
  --build-arg NO_PROXY=localhost,127.0.0.1 \
  -t myimage .

Dockerfile 里不需要声明这些 ARG——Docker 对这几个变量名有内置支持。

场景三:容器运行时要联网

docker run -it \
  -e HTTP_PROXY=http://host.docker.internal:7897 \
  -e HTTPS_PROXY=http://host.docker.internal:7897 \
  -e NO_PROXY=localhost,127.0.0.1,::1 \
  --add-host=host.docker.internal:host-gateway \
  ubuntu bash

docker-compose 的写法:

services:
  app:
    image: myimage
    environment:
      - HTTP_PROXY=http://host.docker.internal:7897
      - HTTPS_PROXY=http://host.docker.internal:7897
      - NO_PROXY=localhost,127.0.0.1,::1,app,db
    extra_hosts:
      - "host.docker.internal:host-gateway"

用宿主机局域网 IP 代替 host.docker.internal

如果 host.docker.internal 不可用,直接用宿主机的局域网 IP:

# Windows 上查
ipconfig
# Linux 上查 docker0 网桥地址(容器视角的宿主机)
ip addr show docker0    # 通常是 172.17.0.1

然后把 host.docker.internal 换成那个 IP。

更省事的方案:开 TUN

上面那些配置加起来不少。如果嫌麻烦,开 TUN 模式——所有流量在网络层被接管,Docker daemon 和容器都不需要任何配置。

两种思路逐个配代理精确可控不影响其他流量要分三处配置,容易漏TUN 模式一劳永逸Docker 完全无感知需要虚拟网卡权限,可能与容器网络冲突
开发机上用 TUN 最省心;服务器上倾向逐个配

TUN 下要注意把 Docker 的网段加入直连规则,避免容器间通信被代理:

prepend-rules:
  - IP-CIDR,172.17.0.0/16,DIRECT,no-resolve
  - IP-CIDR,172.18.0.0/16,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve

WSL2:两种网络模式

WSL2 从某个版本起支持镜像网络模式,两种模式下配置方法完全不同。先确认你用的是哪种。

# 在 WSL2 里执行
cat /etc/resolv.conf
ip route show default

模式一:NAT 模式(默认,传统)

WSL2 有独立虚拟网卡,宿主机对它来说是一个网关地址。

# 自动获取宿主机 IP 并设置代理
export HOST_IP=$(ip route show default | awk '{print $3}')
export HTTP_PROXY="http://$HOST_IP:7897"
export HTTPS_PROXY="http://$HOST_IP:7897"
export ALL_PROXY="socks5://$HOST_IP:7897"
export NO_PROXY="localhost,127.0.0.1,::1,*.local"

写进 ~/.bashrc~/.zshrc 做成开关:

proxyon() {
  local host_ip=$(ip route show default | awk '{print $3}')
  export HTTP_PROXY="http://${host_ip}:7897"
  export HTTPS_PROXY="http://${host_ip}:7897"
  export ALL_PROXY="socks5://${host_ip}:7897"
  export NO_PROXY="localhost,127.0.0.1,::1,*.local"
  echo "proxy on → ${host_ip}:7897"
}
proxyoff() {
  unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY
  echo "proxy off"
}

为什么要动态获取 IP:WSL2 的虚拟网卡地址每次重启宿主机都可能变,写死会失效。

模式二:镜像网络模式(较新的 Windows)

%USERPROFILE%\.wslconfig 里启用:

[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true
firewall=true

改完执行 wsl --shutdown 重启 WSL。

镜像模式下 WSL2 和宿主机共享网络命名空间,可以直接用 127.0.0.1

export HTTP_PROXY="http://127.0.0.1:7897"
export HTTPS_PROXY="http://127.0.0.1:7897"

autoProxy=true 还会让 WSL 自动继承 Windows 的系统代理设置,很多情况下连环境变量都不用配。

两种 WSL2 网络模式NAT 模式独立虚拟网卡需要动态获取宿主机 IP需要放行防火墙兼容性好镜像模式共享宿主机网络直接用 127.0.0.1可自动继承系统代理需要较新的 Windows
能用镜像模式就用镜像模式,省掉一大堆配置

验证代理是否生效

# 看环境变量
env | grep -i proxy

# 实测
curl -I https://www.google.com

# 看出口 IP(应该是节点的 IP)
curl https://api.ipify.org

如果 curl 通了但 aptpip 还是不行,说明那些工具有自己的代理配置,见开发工具代理速查

排查清单

连不上时按顺序查Clash 的 allow-lan 开了吗(netstat 看是否 0.0.0.0)Windows 防火墙放行了吗容器端口号和 Clash 里的混合端口一致吗NO_PROXY 里排除了内部服务名和内网段吗Docker 的三个场景(daemon

一条快速验证命令,在容器或 WSL 里执行:

curl -v --connect-timeout 5 http://宿主机IP:7897

能连上(哪怕返回 400)说明网络层通了;Connection refused 说明 allow-lan 或防火墙有问题。

小结

  • 第一步永远是开 allow-lan + 放行防火墙
  • Docker 的三个场景要分别配:daemon、build、run
  • host.docker.internal 在 Linux 上需要 --add-host
  • WSL2 先确认网络模式:NAT 要动态取网关 IP,镜像模式直接用 127.0.0.1
  • NO_PROXY 别忘了写内网段和服务名
  • 嫌麻烦就开 TUN,但要把 Docker 网段加进直连规则

相关:开发工具代理速查TUN 底层原理


相关文档