開發與 AI · Clash 技術部落格

Docker 與 WSL2 怎麼走 Clash 代理?映像檔拉取超時與網路設定

docker pull、WSL2 下載與容器內請求由不同處理程式發起。根據發生錯誤位置檢查主機位址和對應代理設定,為建置或容器單獨傳入變數,並用 NO_PROXY 保留資料庫與內部服務直連。

  • Docker
  • WSL2
  • 開發環境
本文目錄

開發環境最容易設錯的地方,是把電腦上可用的代理位址直接複製到所有終端機與容器。真正需要確認的是:哪個程序發出錯誤,它能否連到代理所在的主機。連線測試通過後再儲存長期設定,也要讓資料庫等內部服務保持直連。

docker pull、WSL 下載與容器請求的代理設定

發生錯誤由哪個程式發起?

失敗動作發起請求的程式
curl / apt / git 在 WSL 裡超時WSL 發行版中的處理程序
docker pull 超時Docker Desktop 或 Docker Engine 守護處理程序
RUN apt-get 在 build 時超時BuildKit / 建置容器
啟動後的應用請求失敗執行中的容器

Windows 上的 Clash 監聽 127.0.0.1,只保證 Windows 本機能存取。WSL2 預設執行在 NAT 虛擬網路裡,容器也有獨立的網路環境;它們存取 127.0.0.1 時通常連線的是自己,不是宿主機。

Windows、WSL2 與容器之間的代理路徑
  1. Windows 上的 Clash監聽區域網路可達的 mixed-port
  2. WSL2使用主機位址存取該連接埠
  3. Docker 建置顯式接收 HTTP_PROXY 和 HTTPS_PROXY
  4. 容器內工具再處理 Git、npm 或套件管理員

Windows、WSL2 和各個容器存取 127.0.0.1 時,通常連接的是各自的網路環境。代理位址應填寫目前環境能存取的宿主機位址。

讓 WSL 能存取 Windows 的代理連接埠

先在 Clash 查看實際的 HTTP 或 mixed-port,常見示例是 7890,但你的用戶端可能不同。WSL 使用主機 IP 存取時,這個連線會被當作區域網路連線,用戶端需要允許 LAN 存取,並監聽 WSL 能到達的位址。

允許 LAN 會擴大連接埠可達範圍。只在可信的家庭或單位私有網路使用,並讓 Windows 防火牆限制來源;不要把無認證代理暴露到公共 Wi-Fi 或公用網路。完成測試後若不再需要,可以關閉 LAN 存取。

預設 NAT 與鏡像網路的主機位址

預設 NAT 模式下,可以在 WSL 讀取預設路由的下一跳,它通常就是 Windows 主機在 WSL 虛擬網路中的位址。Windows 11 22H2 及後續版本啟用 mirrored networking 後,WSL 可以直接透過 127.0.0.1 存取 Windows 服務。

WSL 預設 NAT 測試,7890 是待替換的 Clash 連接埠
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 shell 的 HTTP_PROXY 與 HTTPS_PROXY

目前 WSL shell 臨時生效,7890 是連接埠佔位值
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

暫時變數供目前終端機啟動的程式讀取。用 git 或 curl 重做同一 HTTPS 請求,成功後再依 shell 類型寫入自己的啟動檔案;curl 存取 HTTP 位址時讀取小寫 http_proxy,不能只靠 HTTP_PROXY。

apt 的 HTTP 傳輸讀取小寫 http_proxy、no_proxy,或自己的 Acquire::http::Proxy 設定;用 sudo 啟動時還要確認環境是否保留。不要把上方變數段當成所有工具通用的代理設定。

Windows 支援的 WSL 版本也可以在 .wslconfig 使用 autoProxy=true,讓 WSL 匯入 Windows 的 HTTP 代理資訊。啟用後要重啟 WSL,並檢查實際變數值。

NO_PROXY 應包含只在 WSL 內部提供的服務,避免存取 localhost 時繞到 Windows 代理。公司內部網域和私有網段是否加入,要按實際網路決定。

Docker Desktop 與獨立 Engine 的代理入口

Docker Desktop 拉取鏡像與 WSL shell 下載由不同處理程序發起。只在 WSL 中 export HTTP_PROXY,不會自動設定 Desktop 的鏡像拉取。

開啟 Docker Desktop 的 Settings,在 Resources / Proxies(標籤可能隨版本變化)填寫主機可用的 HTTP、HTTPS 代理,並應用設定。

頁面分為 Docker Desktop proxy 和 Containers proxy 時,拉取映像檔要檢查 Containers proxy;只有 Containers proxy 未設定時,Docker Desktop proxy 才作為備援。修改後用 docker pull 驗證。

Docker 官方文件明確說明,Desktop 不讀取 daemon.json 中的守護處理程序代理設定。不要因為 WSL 終端已經能存取,就跳過 Docker Desktop 自己的代理設定。

若使用的是獨立 Linux Docker Engine,而不是 Docker Desktop,才按 Engine 文件在 daemon.json 或 systemd 環境中設定守護處理程序代理,並重啟 Docker 服務。先確認自己執行的形態,避免改了一個根本不被讀取的檔案。

為映像檔建置和執行容器分別傳入代理

Docker 的用戶端設定可以為新容器和建置自動注入代理環境,也可以在單次命令裡顯式傳入。建置時用 --build-arg,執行階段用 --env;不要在 Dockerfile 裡用 ENV 固化帶認證資訊的代理位址,映像檔歷史和設定可能把它留下。

下方範例在含有 Dockerfile 的專案目錄中執行,demo-app 是這次建置的映像檔名稱,可依自己的專案替換。這不是獨立連通測試;先用前文的 curl 檢查代理連接埠是否可達。

Docker Desktop 既有專案範例,7890 是待替換的 Clash 連接埠
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-app

Docker 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 的網路步驟不再超時
  • 執行容器既能存取外部網路,也能直連內部服務

參考資料