問題形狀:為什麼 Clash 正常,Docker 卻像「沒開代理」
許多人在 macOS 或 Windows 上已用 Clash/Clash Verge Rev 把瀏覽器、IDE 更新與部分桌面程式都帶上節點,主觀感受是「網路已經通了」。但一回到終端機執行 docker pull、docker build,畫面卻卡在初始連線、層下載極慢,或直接報錯逾時。這種割裂很常見,原因並不一定是 Docker Hub 當天特別不穩,而是Docker Engine 拉映像、建置映像、以及容器執行這三條路徑,各自對「要不要讀 HTTP_PROXY」的規則並不相同;它們也不會自動去用你在 Clash 裡設定的「系統 Proxy」,除非你明確寫進引擎設定或把變數傳進建置/執行環境。
本文聚焦容器走宿主機代理裡最直白、也最可複製的一條路:讓需要連到公網 registry 的流量,改走主機上 Clash 對外開放的 HTTP 代理埠(常見為 mixed-port: 7890,實際請以你的設定為準)。這與本站 TUN 模式把整機流量納管 的策略不同:後者偏向「能進核心的封包都先經過虛擬介面」;本文則是「不改 TUN,只把 Docker 相關程序指到 http://主機位址:7890」,適合已在圖形用戶端跑穩 Clash、只想把容器與建置流程補齊的人。若你主要是在 WSL2 裡打指令而非 Docker Desktop 的 Linux VM,可併讀 WSL2 與 Windows 主機 Clash 一篇,兩者場景相鄰但網路命名空間不同。
三條路要分開設定:引擎拉映像、docker build、執行中的容器
實務上請把需求拆成三塊,避免「改了一處以為全部生效」。第一,Docker daemon 自己向 Docker Hub 或其他 registry 拉映像時,讀的是引擎組態(常見為 daemon.json 裡的 proxies),不是你在 shell 隨手 export 的變數。第二,docker build 預設會另外起建置環境;BuildKit 時代下,若要讓 RUN apt-get、RUN curl 這類步驟走代理,通常要把 HTTP_PROXY/HTTPS_PROXY 以 build-arg 或組態檔傳入。第三,已經 docker run 起來的長服務,若要在容器內抓公網套件,則要在該次執行或 Compose 的 environment 區塊帶入同一組變數。少做其中一環,就會出現「pull 已經快了,build 卻仍卡住」這種半套成功。
主機位址怎麼填:host.docker.internal 與 Linux 宿主閘道
在 Docker Desktop for Mac/Windows 上,容器內要連回「跑 Docker 的那台實體機」時,優先使用內建主機名 host.docker.internal。它會解析到可從容器路由到的主機位址,讓你把代理寫成 http://host.docker.internal:7890 而不用每次手動查 IP。若你在純 Linux 上跑 Docker Engine、沒有 Desktop 幫你維護這個名稱,可以於 docker run 加上 --add-host=host.docker.internal:host-gateway(或於 Compose 使用對應的 extra_hosts),讓自建環境也能沿用同一套字串,減少文件與腳本分叉。
無論哪一種平台,請先確認 Clash 在主機上確實監聽了你寫進 Docker 的那個埠,且已開啟「允許區網連線」(Allow LAN 或同等選項),否則容器即使能解析 host.docker.internal,連線仍會在 TCP 層被拒。Windows 使用者若曾遇連接埠衝突,可先對照 7890/mixed-port 排查 一文,再回來改 Docker 組態。
設定 Docker Engine 代理:daemon.json 的 proxies
讓 docker pull、docker push 這類由守護行程發起的連線走 Clash,請在 Docker Engine 組態中加入 proxies 區塊(路徑依安裝方式而異:Desktop 可在設定介面對應到 JSON,Linux 常見為 /etc/docker/daemon.json)。下列為示意,請將埠號改成你的 mixed-port 或獨立 HTTP 埠:
{
"proxies": {
"default": {
"httpProxy": "http://host.docker.internal:7890",
"httpsProxy": "http://host.docker.internal:7890",
"noProxy": "localhost,127.0.0.1,::1"
}
}
}
修改後需要重啟 Docker 才會套用。若你公司內有私有 registry,請把其主機名或網段補進 noProxy,避免內部倉庫流量被誤送到公開節點。完成後可用 docker pull hello-world 這類小映像驗證;同時在 Clash 的連線紀錄裡應能看到來自 bridge 網段、目標為 registry 的 HTTP CONNECT 命中,這代表Docker Clash 代理路徑真的接通。
docker build 與 BuildKit:用 --build-arg 傳 HTTP_PROXY
建置過程中的每一道 RUN 指令,其網路堆疊與你筆電 shell 預設無關。啟用 BuildKit 時,建議明確傳入:
docker build \
--build-arg HTTP_PROXY=http://host.docker.internal:7890 \
--build-arg HTTPS_PROXY=http://host.docker.internal:7890 \
--build-arg NO_PROXY=localhost,127.0.0.1 \
-t myimage:local .
若專案裡已有 Dockerfile,也可在開頭使用 ARG HTTP_PROXY 等宣告,讓 CI 與本機共用同一參數名稱。重點是:不要假設「daemon 已設代理,build 就一定跟著走」——在許多版本組合下,兩者是分開的。
docker compose 與執行中容器
對長駐服務,可在 Compose 的服務區塊加入:
environment:
HTTP_PROXY: http://host.docker.internal:7890
HTTPS_PROXY: http://host.docker.internal:7890
NO_PROXY: localhost,127.0.0.1
若僅少數一次性容器需要代理,也可用 docker run -e HTTP_PROXY=...。請記得 NO_PROXY 要涵蓋你不希望經過 Clash 的內部 API 位址,否則除錯時會看到奇怪的連線延遲或憑證錯誤。
與 Docker Desktop「鏡像加速」並用會不會衝突?
在中國大陸等環境,許多人會在 Docker Desktop 或 daemon.json 設定registry mirrors,讓拉取改走國內快取節點。Clash 的 HTTP 代理與鏡像加速是不同層次:前者決定「這條 TCP 連線要不要經過你指定的 HTTP CONNECT 代理」,後者決定「解析哪一個 mirror 的位址來下載層資料」。兩者可以並存;若 mirror 本身已能極速直連,你也可以把該 mirror 的主機名加進 noProxy,讓流量不必再繞一圈本機 Clash,減少延遲。反之,若 mirror 仍需跨境,就讓它走代理。實務上以實測拉一層大映像的總耗時為準,而不是死記口訣。
建議排查順序(濃縮版)
- 確認 Clash 正常、mixed-port(或 HTTP 埠)數值正確,且已允許區網連線。
- 從任一容器內
curl -v --proxy http://host.docker.internal:7890 https://example.com測試代理可達性(依你的測試網域替換)。 - 設定
daemon.json的proxies,重啟引擎後再docker pull。 - 為
docker build補上--build-arg HTTP_PROXY/HTTPS_PROXY。 - 為常駐服務在 Compose/
run -e帶入相同變數,並維護好NO_PROXY。 - 必要時再調整 registry mirror 與
noProxy的取捨,並用 Clash 日誌核對規則命中。
127.0.0.1:7890;完整服務化部署可延伸閱讀 Ubuntu 上 Clash Meta 與 systemd。本文則鎖定「主機圖形用戶端已開 Clash、Docker 在另一層網路命名空間」這種最常見的桌面開發情境。
結語:把 Docker 納入你已驗證過的 Clash 出口
相較於盲目更換節點或重裝 Docker,先把「引擎/建置/執行」三條代理路徑拆開檢查,通常能一次解決大半 Docker pull 逾時 的困擾。當 HTTP_PROXY 與 HTTPS_PROXY 都穩定指向主機上的 Clash HTTP 埠,再配合合理的 NO_PROXY 與可選的 Docker Desktop 鏡像加速,本機容器開發體驗會明顯收斂到可預期的狀態。若你希望先取得整理好的多平台用戶端與更新說明,建議從本站下載頁選擇對應系統,並搭配 說明與教學文件 建立長期可維護的設定習慣;相較於四處搜尋來路不明的安裝包,這條路徑通常更安全、也更容易跟上核心版本。→ 立即免費下載 Clash,開啟流暢上網新體驗