跳到主要內容

首頁 / 部落格 / 部署實戰

讓 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 底層原理


相關文件