Docker 映像檔下載逾時,未必代表 Registry 故障,也不一定是代理節點速度不足。當 Docker daemon、容器網路、DNS 與 Clash 分別位於不同的網路命名空間時,瀏覽器可以正常使用代理,Docker 卻仍然可能直接連線,最後卡在 context deadline exceeded、i/o timeout 或 Client.Timeout exceeded while awaiting headers。本文從封包流向與 Linux 網路架構開始,示範如何以 Clash 或 Mihomo 為主機與容器提供透明代理,並整合 TUN、iptables、DNS、daemon.json 與 YAML 規則,改善映像檔拉取失敗、容器連線逾時及 DNS 洩露問題。
先理解 Docker 透明代理的封包流向
一般 Linux 主機上,Docker daemon 通常由 root 權限執行,容器則透過 Docker 建立的 bridge 網路連線。瀏覽器的流量可能經由 Clash 的系統代理設定送出,但 Docker daemon 不會自動讀取桌面環境中的 HTTP 或 SOCKS 設定。因此,即使 Clash Verge、Clash for Windows 或 Mihomo 已經能讓瀏覽器開啟外部網站,執行 docker pull 時仍可能完全繞過代理。
一個典型的拉取流程如下:Docker CLI 先向本機 daemon 發送請求;daemon 解析 Registry 域名,連線至認證服務,再依照返回的 Manifest 找到各個 layer 的下載位置。任何一個階段使用了錯誤的 DNS、沒有經過代理,或代理不支援該連線,都可能使整個映像檔下載失敗。
透明代理的目標不是修改每個應用程式的代理參數,而是在封包離開主機或容器前攔截它。Clash 取得原始目的地後,再依照域名、IP 或規則集選擇直連與代理。這種方式特別適合 Docker,因為不需要為每個容器分別設定環境變數,也能覆蓋由應用程式自行建立的 TCP 連線。
- 主機流量:由作業系統路由表送往 Clash 的 TUN 介面,或被 iptables 的 REDIRECT/TPROXY 規則攔截。
- 容器流量:先從容器的虛擬介面進入 Docker bridge,再經過主機的 FORWARD 與 NAT 鏈,最後交給 Clash 處理。
- DNS 流量:若容器直接使用宿主機或外部 DNS,可能在代理之外解析域名,造成污染或洩露。
- Docker daemon 流量:它不一定經過容器 bridge,通常需要另外透過 TUN、iptables 或 daemon 專用代理設定覆蓋。
TUN 與 iptables:兩種方案如何選擇
TUN 模式會建立一個虛擬三層網路介面,Clash 將系統流量導入介面後,根據 IP 封包還原出連線資訊,再交給代理核心。對 Docker 主機而言,TUN 通常是較容易維護的方案,因為它可以透過自動路由覆蓋主機上的大部分 TCP、UDP 流量,不必手動建立大量 NAT 規則。
iptables 方案則是在核心的 netfilter 層攔截流量。REDIRECT 適合 TCP 流量,TPROXY 則能保留原始目的地址,並可處理更複雜的透明代理情境。它的優點是控制細緻、適合伺服器或路由器;缺點是需要處理 Docker 自有鏈、FORWARD 政策、回程路由以及 root 使用者例外,排錯成本明顯較高。
- 優先選 TUN:單機使用、希望快速讓 Docker daemon 與容器共用代理,且使用的是支援 Mihomo TUN 的客戶端。
- 考慮 iptables:需要精確區分容器、主機服務與特定使用者,或主機本身就是網關與多個 Docker 網段的出口。
- 不要混用兩套攔截邏輯:同時啟用不完整的 TUN 與 REDIRECT 規則,可能造成迴圈、重複代理或連線無法建立。
tun:
enable: true
stack: system
device: mihomo
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
- tcp://any:53
dns:
enable: true
listen: 0.0.0.0:1053
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- https://223.5.5.5/dns-query
fallback:
- https://1.1.1.1/dns-query
- https://8.8.8.8/dns-query
fallback-filter:
geoip: true
geoip-code: TW
auto-route 讓核心嘗試建立系統路由,auto-detect-interface 則用於在多張網卡、VPN 或雲端主機環境中選擇正確的出口。dns-hijack 只能攔截抵達 Clash 的 DNS 請求,不能取代所有容器內的 DNS 設計,因此後續仍應檢查 Docker 的 resolver 設定。
實作:設定 Docker daemon 與容器網路
以下以 Linux 主機上的 Mihomo 為例。操作前請先備份配置,確認 Clash 的管理介面可正常使用,並記錄目前的網卡名稱、Docker bridge 網段及 DNS 監聽埠。若主機上有 NetworkManager、 ufw、firewalld 或其他 VPN,請特別留意它們可能覆蓋路由與防火牆規則。
- 先以
ip route和docker network inspect bridge查看預設出口與 Docker 網段,例如172.17.0.0/16。 - 在 Clash 配置中啟用 TUN、DNS 與必要的代理規則,重新載入配置後,確認虛擬介面已出現在
ip addr的輸出中。 - 建立或修改
/etc/docker/daemon.json,讓 Docker daemon 使用本機 HTTP 代理。這是補強方案,不能取代透明代理。 - 重新啟動 Docker,先測試 Registry 的 DNS、HTTPS 連線,再執行映像檔拉取。
- 最後在臨時容器內驗證 DNS 與外部連線,確認容器流量沒有繞過 Clash。
{
"proxies": {
"http-proxy": "http://127.0.0.1:7890",
"https-proxy": "http://127.0.0.1:7890",
"no-proxy": "localhost,127.0.0.1,::1,172.17.0.0/16,192.168.0.0/16"
}
}
上例的 7890 只是示意,請換成目前 Clash 的 HTTP 混合代理埠。若 Docker daemon 在獨立的 systemd 服務中執行,這個設定會影響 daemon 拉取映像檔,但不會自動套用到所有容器。修改後可執行 sudo systemctl daemon-reload 與 sudo systemctl restart docker,再用 docker info 檢查 Proxies 欄位是否出現。
若 Clash 只監聽 127.0.0.1,宿主機上的 Docker daemon 可以使用它;但若你把 Docker daemon 放進另一個容器,或希望其他容器直接連線到 Clash,就必須讓 Clash 監聽 Docker bridge 可達的地址,例如宿主機的 bridge IP,並設定防火牆限制來源。不要在沒有驗證的情況下把控制介面與代理埠暴露到公網。
docker run --rm busybox cat /etc/resolv.conf docker run --rm busybox nslookup registry-1.docker.io docker run --rm curlimages/curl -I https://registry-1.docker.io/v2/ docker pull hello-world
測試時不要只看 ping。許多 Registry 不回應 ICMP,但 HTTPS 完全正常;相反地,能 ping 通某個 IP 也不代表 TLS、SNI、認證服務與 layer 下載都沒有問題。若 nslookup 得到的是錯誤地址,先修正 DNS;若 DNS 正常但 HTTPS 逾時,再查看 Clash 連線頁面與規則命中情況。
為 Docker Registry 設計 YAML 規則
映像檔拉取通常不只連線一個域名。Docker Hub 可能涉及 Registry、Token 認證與 CDN;GHCR、GitLab Registry、Google Artifact Registry 也可能把 layer 分散到不同的主機。因此,只把 docker.io 加入規則往往不夠。建議先從 Clash 的連線記錄找出實際域名,再建立明確的 Registry 規則。
rules:
- DOMAIN-SUFFIX,docker.io,Docker
- DOMAIN-SUFFIX,docker.com,Docker
- DOMAIN-SUFFIX,dockerstatic.com,Docker
- DOMAIN,registry-1.docker.io,Docker
- DOMAIN-SUFFIX,ghcr.io,Docker
- DOMAIN-SUFFIX,githubusercontent.com,Docker
- DOMAIN-SUFFIX,quay.io,Docker
- DOMAIN-SUFFIX,gcr.io,Docker
- DOMAIN-SUFFIX,googleapis.com,Docker
- DOMAIN-SUFFIX,local,DIRECT
- IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
- MATCH,DIRECT
proxy-groups:
- name: Docker
type: select
proxies:
- 自動選擇
- DIRECT
規則名稱必須與策略組名稱完全一致,且規則順序會影響結果。把廣泛的 MATCH,DIRECT 放在 Docker 規則之前,會使後面的規則永遠沒有機會命中。若某個內部 Registry 位於公司網路,應使用更精確的 DOMAIN 或 IP-CIDR 規則指定直連,避免把內部服務送到外部節點。
處理逾時、DNS 洩露與常見衝突
如果 docker pull 仍然逾時,可以按「解析、建立連線、下載資料」三個階段逐一排查。解析階段使用 getent hosts registry-1.docker.io 或容器內的 nslookup;建立連線階段使用 curl -Iv 觀察 TCP 與 TLS;下載階段則查看是否只有特定 layer 失敗。不同階段的症狀相似,但修復方向完全不同。
- 只有 Docker daemon 失敗:檢查
daemon.json的 JSON 格式、代理埠、systemd 重啟狀態,以及 daemon 是否使用了獨立的環境設定。 - 主機成功、容器失敗:檢查 Docker bridge 是否被 TUN 路由覆蓋、FORWARD 政策是否為 DROP,以及容器的 DNS 是否指向不可達的地址。
- 解析成功但 HTTPS 逾時:檢查 Registry 域名是否命中正確策略組,並確認代理節點允許長時間、大檔案及 HTTP/2 或 TLS 連線。
- 下載到一半中斷:檢查節點頻寬、MTU、連線保持時間與 CDN 域名規則。跨境鏈路可能需要降低 MTU,避免分片封包被丟棄。
- 出現代理迴圈:確認 Clash 自己的出站連線沒有再次被 TUN 或 REDIRECT 攔截,並將代理伺服器地址、區域網路與保留地址加入直連或排除清單。
DNS 洩露常見於容器直接使用 8.8.8.8、路由器 DNS 或雲端供應商 DNS。這些查詢可能不經 Clash,導致域名解析結果與代理出口不一致。可讓 Docker 使用宿主機上可達的 Clash DNS 服務,或讓 TUN 的 DNS 劫持接管容器的 UDP、TCP 53 流量。不過,若 Clash DNS 只綁定 loopback,容器無法直接存取;此時應調整監聽地址並用防火牆限制來源,而不是盲目開放到所有網路。
另外,fake-ip 可能與少數需要真實 IP 的服務衝突,例如內部服務發現、部分 VPN、STUN 或特殊註冊中心。遇到這類問題,可把對應域名加入 fake-ip-filter,並為內部網域設定直連規則。不要因為單一服務異常就整體關閉 fake-ip,否則 Docker 的域名規則匹配與 DNS 防污染效果也會一併降低。
安全性與長期維護建議
透明代理會擴大 Clash 的影響範圍,因此完成設定後應重新檢查監聽埠與權限。HTTP、SOCKS 與混合代理埠若監聽在 0.0.0.0,區域網內任何裝置都可能使用你的出口;External Controller 更不能在沒有密鑰的情況下公開。建議代理埠只允許 Docker bridge 與受信任的管理網段存取,API 則限定在 127.0.0.1 或設定強度足夠的 secret。
配置變更應採用小步驟方式進行:先測試主機 TUN,再測試 Docker daemon,接著測試單一容器,最後才套用到生產服務。每次修改後保留 docker info、ip route、DNS 查詢與 Clash 連線記錄,方便快速比較差異。對經常拉取大型映像檔的 CI 主機,也可以設定本地 Registry mirror 或拉取快取,減少對外部 CDN 的依賴,但 mirror 本身仍應加入正確的 DNS 與代理規則。
常見問題 FAQ
瀏覽器可以開網站,為什麼 Docker 仍然逾時?
瀏覽器通常讀取系統代理或 Clash 客戶端設定,Docker daemon 則是獨立的背景服務,不會自動繼承桌面代理。請同時設定 TUN 或透明代理,並在 daemon.json 中配置 daemon 使用的代理,重啟 Docker 後再用 docker info 驗證。
啟用 TUN 後,還需要 iptables 嗎?
多數單機情境不需要再建立 REDIRECT 規則,先使用 TUN 的自動路由即可。若容器網段沒有被正確導入、主機是複雜網關,或需要按來源精細控制,才考慮加入 iptables。兩者混用前必須確認攔截鏈與排除規則,避免迴圈。
Docker Registry 應該加入哪些域名?
至少先檢查實際連線,Docker Hub 常見 registry-1.docker.io、auth.docker.io 及相關 CDN;GHCR、Quay、GCR 則有各自的域名。不要只憑固定清單配置,應以 Dashboard 連線記錄補充規則,並把規則放在 MATCH 之前。
fake-ip 會讓容器服務失效嗎?
一般 HTTPS 與映像檔拉取通常可以正常工作,但少數依賴真實 IP、區域網路廣播或 STUN 的服務可能不相容。可將內部網域、*.lan、*.local 及特定服務加入 fake-ip-filter,再用直連規則處理,而不必關閉整個 fake-ip 模式。
完成以上設定後,Docker 的代理路徑、DNS 解析與 Clash 規則便能形成一致的鏈路。若你還沒有安裝合適的 Clash 或 Mihomo 客戶端,可以先免費下載,再依照實際作業系統與網路拓撲逐步套用本文配置。