本文目錄
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 引擎、建置過程和執行容器。哪一項仍失敗,就回到那一層的設定,不必重新改已經透過的其他三層。
