Clash Docker 透明代理進階設定:排查映像檔下載逾時

Docker Hub、GHCR 與套件註冊表連線不穩時,問題往往來自容器網路、DNS 解析或代理規則,而非單純節點速度。本指南以 Mihomo 為例,說明 TUN、redir-host、Docker bridge 與 rule-providers 的整合方式,並附上可套用的 YAML、檢查指令及安全設定。

先釐清 Docker 透明代理的封包路徑

Docker 映像檔下載逾時,常被誤判為 Clash 節點速度不足,但實際上可能在多個不同環節發生。執行 docker pull 時,請求通常不是由正在執行的應用程式容器發出,而是由 Docker daemon 負責連線 Registry。也就是說,容器內設定的 HTTP_PROXYHTTPS_PROXY,不一定會影響 docker pull;反過來,Docker daemon 已設定代理,也不代表容器內的套件管理器會自動使用相同代理。

一個完整的排查路徑可以拆成四段:Docker CLI 將請求交給 daemon、daemon 解析 Docker Hub 或 GHCR 網域、daemon 連線 Registry 與認證服務,最後下載 manifest、layer 與簽章資料。Docker Hub 可能涉及 registry-1.docker.ioauth.docker.io 以及 CDN 網域;GHCR 則通常會使用 ghcr.io、GitHub API 或物件儲存 CDN。因此,只允許其中一個網域通過規則,仍可能在取得 Token 或下載 layer 時逾時。

流量來源 常見目的 主要代理設定位置
Docker daemon docker pull、映像檔推送與 Registry 認證 systemd drop-in、Docker Desktop 設定或 daemon.json
建置容器 aptnpmpipgo mod BuildKit 參數、Dockerfile ARG 或建置環境
執行中的容器 應用程式 API、外部套件與更新服務 容器環境變數、網路模式與應用程式設定
宿主機 mihomo 接收 HTTP、SOCKS 或 TUN 轉送流量 mixed-port、TUN、路由與規則設定

建立宿主機 mihomo 透明代理基礎

在 Linux 宿主機上,較容易維護的架構是由 mihomo 負責代理出站流量,Docker daemon 透過宿主機可達的 HTTP 或 SOCKS 連接埠使用代理。若需要接管不支援代理環境變數的程式,再額外啟用 TUN。不要一開始同時啟用多個透明代理工具、iptables 轉送規則與 TUN,否則很難判斷封包究竟在哪一層被重導。

以下是一組適合單機測試的核心設定片段。mixed-port 提供 HTTP 與 SOCKS 混合代理,allow-lan 讓 Docker bridge 網段可以連到宿主機;若只把連接埠繫結在 127.0.0.1,容器通常無法直接使用它。實際部署時應使用防火牆限制來源,不要無限制暴露代理連接埠。

mixed-port: 7890
allow-lan: true
bind-address: "*"
mode: rule
log-level: info

external-controller: 127.0.0.1:9090
secret: replace-with-a-long-secret

dns:
  enable: true
  listen: 0.0.0.0:1053
  ipv6: false
  enhanced-mode: fake-ip
  nameserver:
    - https://1.1.1.1/dns-query
    - https://dns.google/dns-query

若採用 TUN,請確認目前的 mihomo 版本與作業系統核心都支援所需功能,再逐項開啟自動路由、嚴格路由與 DNS 劫持。TUN 不是單純的「代理開關」,它會改變系統路由與 DNS 流程。設定錯誤時,可能造成 mihomo 自己的控制連線被再次導回 TUN,形成迴圈。

tun:
  enable: true
  stack: system
  auto-route: true
  auto-detect-interface: true
  strict-route: true
  dns-hijack:
    - any:53
    - tcp://any:53

Docker bridge 與宿主機位址

Linux Docker 容器通常位於 172.17.0.0/16 或自訂 bridge 網段。容器中的 127.0.0.1 指向容器自身,不是宿主機,因此不能把代理寫成 http://127.0.0.1:7890。可以使用 Docker bridge 的閘道位址,例如透過 ip route 查看:

ip route
docker network inspect bridge
ss -lntp | grep 7890

在許多 Linux 預設環境中,容器可用宿主機 bridge 位址 172.17.0.1 連線,但這不是所有自訂網路都固定相同。使用 Docker Compose 時,也可以加入宿主機映射,然後以固定名稱存取;不過 host-gateway 主要解決名稱解析,仍要確認宿主機代理服務確實監聽在可達的介面上。

services:
  worker:
    image: example/worker:latest
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      HTTP_PROXY: http://host.docker.internal:7890
      HTTPS_PROXY: http://host.docker.internal:7890
      NO_PROXY: localhost,127.0.0.1,.local

設定 Docker daemon 的出站代理

處理 docker pull 最重要的是設定 daemon,而不是只在目前終端機執行 export HTTPS_PROXY=...。在使用 systemd 的 Linux 主機上,可以建立 Docker 服務的 drop-in 檔案。以下範例假設 mihomo 的 HTTP 代理位於宿主機 127.0.0.1:7890;如果 Docker daemon 在另一台機器或獨立虛擬機中執行,則必須改成該 daemon 能連線的宿主機位址。

sudo mkdir -p /etc/systemd/system/docker.service.d

sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf >/dev/null <<'EOF'
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1,::1,.local"
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show --property=Environment docker

修改後先用一個小型公開映像測試,不要直接以大型映像作為唯一判斷依據。若 daemon 沒有讀到環境變數,systemctl show 通常能立即揭露問題。若使用 Docker Desktop,代理設定通常由 Desktop 的設定介面管理,直接修改 Linux 主機上的 systemd 檔案未必會影響 Desktop 內部的 daemon。

代理服務使用 HTTPS 連接埠時,URL 方案必須與實際服務一致。mihomo 的 mixed-port 多數情況是以 HTTP 代理協定接收 CONNECT 請求,即使目標網址是 HTTPS,Docker daemon 的代理 URL 仍可寫成 http://宿主機:7890。不要因為目標是 HTTPS,就擅自將代理 URL 改成 https://;這會讓 daemon 嘗試以 TLS 連線到一個其實只提供純 HTTP 代理的連接埠。

Docker daemon 與容器代理不要混淆

Docker daemon 的設定只影響映像檔拉取、推送與部分 Registry 操作,不會自動注入每一個容器。容器需要代理時,應在 Compose、執行命令或建置流程中明確傳入。反過來,容器中的環境變數也不會修正 daemon 的 Registry 連線。

docker run --rm \
  -e HTTP_PROXY=http://host.docker.internal:7890 \
  -e HTTPS_PROXY=http://host.docker.internal:7890 \
  -e NO_PROXY=localhost,127.0.0.1,host.docker.internal \
  curlimages/curl:latest \
  -I https://registry-1.docker.io/v2/

回應 401 Unauthorized 不一定是故障。Docker Registry 常用未認證的 /v2/ 回應告知客戶端前往 Token 服務,這反而證明 DNS、TCP、TLS 與基本 HTTP 路徑已經走通。真正需要注意的是連線逾時、TLS handshake timeout、connection reset 或無法解析主機名稱。

DNS 與分流規則的關鍵排查

透明代理環境中,DNS 解析與實際出站路徑必須保持一致。若宿主機使用 mihomo 的 fake-ip,但 Docker 容器仍直接詢問公司 DNS 或路由器 DNS,可能出現解析結果不同、內部網域無法存取,或 Registry 網域解析到在目前網路不可達的位址。若只想先排查 Docker Hub,建議暫時使用簡單的 redir-host 或明確 DNS 設定,確認基本連線後再啟用較複雜的 fake-ip 規則。

先從宿主機與容器分別測試 DNS,不要只在瀏覽器中確認網頁能否開啟:

getent hosts registry-1.docker.io
getent hosts auth.docker.io
getent hosts ghcr.io

docker run --rm busybox nslookup registry-1.docker.io
docker run --rm busybox nslookup ghcr.io

規則模式下,Docker Hub、GHCR、GitHub API 及其 CDN 不應被錯誤送往直連。可以先建立明確的網域規則,再依日誌補充實際出現的 CDN 網域。規則順序由上而下比對,因此自訂的 Registry 規則要放在寬泛的 GEOIP、MATCH 或其他兜底規則之前。

rules:
  - DOMAIN-SUFFIX,docker.io,PROXY
  - DOMAIN-SUFFIX,docker.com,PROXY
  - DOMAIN-SUFFIX,dockerusercontent.com,PROXY
  - DOMAIN-SUFFIX,ghcr.io,PROXY
  - DOMAIN-SUFFIX,github.com,PROXY
  - DOMAIN-SUFFIX,githubusercontent.com,PROXY
  - DOMAIN-SUFFIX,githubassets.com,PROXY
  - MATCH,DIRECT

上述規則名稱中的 PROXY 必須與實際存在的策略組名稱完全一致。若你的策略組叫做「節點選擇」或 Proxy,就必須替換成對應名稱。不要只把所有網域送往代理而忽略內部 Registry;企業環境中的 registry.internal.example、服務發現名稱與私有 DNS,通常應使用 DIRECT 或內部專用策略。

用日誌與分段測試定位逾時

排查時不要一次修改代理、DNS、TUN 和規則。建議先關閉不必要的 TUN,只讓 Docker daemon 使用 mihomo 的 HTTP 代理;確認可以拉取小型映像後,再決定是否需要透明接管。這樣可以把問題縮小到「daemon 代理設定」或「TUN 路由」其中一層。

  1. 在宿主機確認 mihomo 正在監聽 7890,並查看控制介面與核心日誌沒有持續重啟。
  2. curl 經由同一個代理請求 Registry,區分 DNS、TLS 與 HTTP 狀態碼問題。
  3. 重新啟動 Docker daemon,確認 systemd 環境變數已載入。
  4. 先拉取小型測試映像,再測試包含多個 layer 的實際映像。
  5. 若主體映像成功但建置失敗,改查 BuildKit、Dockerfile 與套件管理器的代理設定。
curl -v \
  -x http://127.0.0.1:7890 \
  --connect-timeout 10 \
  --max-time 30 \
  https://registry-1.docker.io/v2/

docker --debug pull hello-world:latest
journalctl -u docker --since "10 minutes ago" --no-pager

mihomo 日誌中的 dial tcp 通常代表建立 TCP 連線階段遇到問題;context deadline exceeded 表示在期限內沒有完成操作,但仍需配合目標網域判讀;tls: handshake timeout 常見於 TLS 握手被阻擋、代理鏈品質不穩或 MTU 不合;no such host 則優先檢查 DNS。若日誌顯示請求走了 DIRECT,而你的網路需要代理,規則比對就是第一個修正方向。

Docker layer 下載時出現逾時,也可能是 MTU 或連線重用問題,尤其是在 TUN、WireGuard、PPPoE 或多層虛擬網路並存的主機上。不要先大幅調整 MTU;應先比較一般 HTTPS、小型映像與大型 layer 的結果,再查看核心網路介面與路由。若只有大檔案在傳輸中途重設,才有理由進一步測試較低的介面 MTU、停用某些鏈路卸載功能,並確認代理節點對長連線的支援。

正式環境的安全與維護方式

測試成功後,應把設定拆成可追蹤、可回復的檔案,不要只依賴手動執行的 export 或臨時 iptables 指令。Docker daemon 的代理設定、mihomo 的核心設定、規則集與防火牆政策應分開備份,並記錄變更時間、版本與回復方式。升級 mihomo 或 Docker 前,先保留目前能正常工作的設定與日誌。

若環境中有私有 Registry,建議明確區分公開與內部網域。公開 Docker Hub、GHCR 可依需求走代理,內部 Registry 則通常應走內網,並在 Docker daemon 的 NO_PROXY 中加入主機名稱、網域後綴與必要的 IP 範圍。NO_PROXY 的格式在不同程式中略有差異,修改後應以實際 daemon 日誌與測試拉取結果確認,不要假設所有元件都完全支援 CIDR。

當 Docker Hub、GHCR 和套件下載都需要穩定通過時,最重要的不是堆疊更多規則,而是確認每個流量來源都有清楚的出口。Docker daemon、BuildKit、執行容器與宿主機 TUN 各自有不同的設定邊界;先沿著封包路徑定位,再用日誌驗證實際分流,才能避免把 DNS 問題誤當成節點問題,也能讓正式環境的透明代理更容易維護。

FlClash 下載入口 查看各平台用戶端