Docker 透明代理不是只把 Proxy 寫進容器

如果 Docker 容器可以解析一般網站,卻在執行 git clonenpm installpip installdocker pull 時反覆逾時,問題通常不只是「代理網址填錯」。容器內的程式、Docker Engine、宿主機本身,以及 DNS 查詢,可能分別走不同的網路路徑。你在宿主機上開啟 Clash 的系統代理,不代表 Docker 容器裡的所有連線都會自動經過 Clash;同樣地,只在容器設定 HTTP_PROXY,也不一定能涵蓋不讀環境變數的套件管理器或背景程序。

本文所說的透明代理,是讓符合條件的容器流量在不修改每個應用程式的前提下,被導向 Clash 的代理入口。這種做法特別適合開發機、CI Runner、NAS 或小型伺服器:你可以讓 GitHub、Docker Hub、套件倉庫等目的地走代理,同時保留公司內網、區域服務與本機網段的直連。若只需要讓單一 CLI 暫時通網,環境變數仍然是較簡單的選項;但當容器數量增加,透明代理與清楚的分流規則會更容易維護。

需要先說明的是,Docker 的透明代理涉及宿主機路由、iptables 或 nftables、容器網段與 DNS 行為。不同 Linux 發行版、Docker rootless 模式、Podman,以及 Clash Verge Rev 與 Mihomo 的功能選項可能不完全相同。下文會採用「先確認流量,再逐層接管」的方式,避免一開始就把所有流量導入 TUN,導致問題難以定位。請在符合所在地法規、公司網路政策及各服務條款的前提下使用代理。

先釐清流量路徑:Docker Engine、容器與 Clash 各自負責什麼

Docker 常見的 bridge 網路會替容器建立一個獨立網段,例如 172.17.0.0/16,再由宿主機進行 NAT。容器發出 HTTPS 請求時,封包首先離開容器的虛擬介面,經過 Docker bridge 與宿主機的轉送規則,最後才從實體網卡送往網際網路。若 Clash 只監聽 127.0.0.1,它通常只能接受宿主機本機程式的連線,容器送到宿主機區網位址的封包並不會自然進入該埠。

因此,Docker 代理可以分成三種層級。第一種是應用層代理,在容器或 Compose 檔案設定 HTTP_PROXYHTTPS_PROXYNO_PROXY;優點是變更範圍小,缺點是程式必須願意讀取這些變數。第二種是Docker Engine 代理,主要影響 Docker daemon 下載映像檔、建立容器時的外部請求,並不等於容器內應用程式已經代理。第三種是網路層透明代理,透過 TUN、策略路由或轉送規則把容器流量交給 Clash,適合希望集中管理的環境。

需求 優先方案 主要注意事項
只讓 Git、curl 或套件工具使用代理 容器環境變數 確認程式支援 HTTPS Proxy,並正確設定 NO_PROXY
Docker daemon 拉不到 Docker Hub 映像檔 設定 Docker Engine 代理 重啟 daemon 後才會生效,既有容器不會因此自動改路由
多個容器與不同工具都要統一分流 Clash 透明代理或 TUN 需處理監聽位址、轉送規則、DNS 與容器網段
開發環境同時有內網與外網服務 透明代理加規則分流 內網、localhost、Docker DNS 不應被錯誤送往遠端節點

這個區分很重要:即使你在 docker-compose.yml 裡加入代理變數,執行 docker pull 時仍可能失敗,因為拉取映像檔的工作通常由宿主機上的 Docker daemon 完成,而非容器內的 Shell。反過來,Docker daemon 已設定代理,也不代表容器內的 git 或 Node.js 應用會沿用同一組設定。排錯時應分別測試這兩條路徑。

開始設定前:先讓 Clash 能接收來自 Docker 網段的流量

在 Clash Verge Rev 或其他 Mihomo 客戶端中,先確認目前載入的是實際生效的設定檔,而不是只在編輯器裡修改的草稿。透明代理的核心不是某一個介面名稱,而是三件事:Clash 是否有可供 Docker 使用的代理入口、入口是否監聽在容器能抵達的位址,以及策略規則是否會把目標網域送到正確的代理群組。

  • 確認入口埠:常見的 mixed-port 同時接受 HTTP 與 SOCKS 請求,適合讓不同工具共用;若使用單獨的 HTTP 埠,請不要把 SOCKS 格式的 URL 填入容器環境變數。
  • 確認監聽位址:若入口只綁定 127.0.0.1,Docker bridge 通常無法直接存取。可依你的網路模型改用宿主機區網位址,或使用 Clash 支援的 TUN/透明代理方式;不要為了方便把服務埠無限制暴露到公網。
  • 確認允許來源:allow-lan 是否開啟、允許來源範圍是否合理,會影響容器與其他區網裝置能否連入。若只是本機開發,建議使用防火牆限制來源,不要把代理入口開給整個網際網路。
  • 確認模式:選擇 Rule 模式,而不是在測試期間直接使用 Global。Rule 模式可以觀察 GitHub、Docker Hub、公司 GitLab 與內部網域各自採用的策略,問題也比較容易重現。
小提示:設定完成後先不要急著改一大串規則。從宿主機與容器各執行一次 curl,再到 Clash 的連線紀錄確認是否看到相同的目的地與策略。能看見請求,才代表流量真的走進 Clash;看到請求但策略錯誤,才是規則排序問題。

動手操作:用 Compose 建立可驗證的代理容器

下面以一個臨時測試容器示範,重點不是提供固定埠號,而是建立一條可逐步驗證的流程。先取得宿主機在 Docker 網路中可達的位址。Linux 上可以使用 ip addrip route 或檢查 Docker bridge 網段;在 Docker Desktop 上,容器與宿主機之間的特殊位址行為則依平台不同,應以官方文件與實際測試為準。不要直接假設 localhost 代表宿主機,因為對容器而言,localhost 指向的是容器自己。

先建立最小 Compose 檔案,將代理變數集中放在環境檔,避免把包含帳號或密碼的代理 URL 提交到 Git 儲存庫:

services:
  toolbox:
    image: alpine:latest
    command: ["sh", "-c", "apk add --no-cache curl git && sleep 3600"]
    environment:
      HTTP_PROXY: ${CLASH_HTTP_PROXY}
      HTTPS_PROXY: ${CLASH_HTTPS_PROXY}
      NO_PROXY: ${NO_PROXY_LIST}
    extra_hosts:
      - "host.docker.internal:host-gateway"

接著在同一個目錄建立只留在本機的 .envhost.docker.internal 在部分 Linux Docker 環境需要透過 host-gateway 對應,代理埠則必須換成你的 Clash 實際監聽埠。若代理入口要求驗證,請把憑證存放在權限受控的秘密管理機制中,不要直接寫進公開 Compose 檔。

CLASH_HTTP_PROXY=http://host.docker.internal:7890
CLASH_HTTPS_PROXY=http://host.docker.internal:7890
NO_PROXY_LIST=localhost,127.0.0.1,host.docker.internal,.local,172.17.0.0/16

啟動後先檢查變數是否存在,再測試一個你確定應該走代理的 HTTPS 目的地。若 curl 失敗,請依序檢查 DNS、容器能否連到宿主機代理埠、Clash 是否在連線紀錄中收到請求,以及該網域最後套用了哪條規則。不要一看到逾時就立即更換節點,否則很容易把「容器沒有進入代理」誤判成「節點品質不好」。

  1. 使用 docker compose up -d 啟動測試服務,確認映像檔本身可以取得。
  2. 使用 docker compose exec toolbox env 檢查代理變數是否被容器繼承。
  3. 使用 docker compose exec toolbox getent hosts github.com 測試 DNS 解析是否成功。
  4. 使用 docker compose exec toolbox curl -I --max-time 15 https://github.com 測試 TLS 連線。
  5. 回到 Clash 連線面板,確認目的地、入站來源與策略群組均符合預期,再測試 Git 或套件管理器。

這種顯式代理方式適合先建立基準線。如果它能工作,而你希望未來不必為每個服務重複填寫變數,再進一步導入透明代理。若顯式代理也無法工作,優先修正 Clash 入口與宿主機防火牆,不要直接切換到更複雜的 TUN。

DNS 防洩漏與規則提供者:讓分流結果可預期

Docker 的 DNS 是透明代理中最容易被忽略的一層。容器通常會使用 Docker 內建的 DNS 轉送器,再由宿主機或上游 DNS 完成解析。若域名在代理前就被錯誤解析、被公司網路改寫,或 DNS 請求走了與 HTTPS 不同的出口,你可能看到「規則明明匹配了,實際連線卻不穩」的情況。Mihomo 的 DNS 設定可依環境選擇 fake-ip、redir-host 或混合策略,但重點是讓代理目的地與 DNS 行為一致,並把內部網域保留給內部解析器。

不要把所有 DNS 查詢都盲目送到同一個公開服務。內網的 git.company.example、服務發現名稱與 Docker Compose 的服務名,往往只能由內部 DNS 或 Docker DNS 解析。建議使用域名分流:內部後綴走內部 DNS,公開的 GitHub、Docker Hub 與套件來源依 Clash 的代理 DNS 策略處理。若環境對 DNS 有嚴格要求,也要同步檢查 IPv6;有些容器先取得 AAAA 記錄,卻因 IPv6 路由不完整而長時間等待,造成看似隨機的逾時。

規則提供者則適合管理會持續變動的網域集合。你可以把開發工具相關網域、容器映像倉庫、公司內部網域分成不同的 Provider,再在主設定檔中以規則順序引用。常見的分組方式如下:

規則集合 可涵蓋的目的地 建議策略
開發平台 GitHub、GitLab、程式碼下載與 Release 資源 穩定代理群組,避免與一般瀏覽流量混用
容器倉庫 Docker Hub、映像檔 CDN 與認證端點 固定可長時間傳輸的節點,觀察大檔下載是否中斷
套件來源 npm、PyPI、RubyGems、Go module Proxy 依團隊所在地與鏡像站可用性分流
內部服務 公司 Git、私有 Registry、區網主機 DIRECT,並置於公開規則之前

規則順序比規則數量更重要。內部網域與私有 Registry 應先於寬泛的第三方規則;對特定網域的明確規則應先於 GEOIP 或 MATCH。更新規則提供者後,記得檢查格式、更新時間與實際載入狀態。若遠端 Provider 暫時無法下載,應保留上一份可用快取,並在更新失敗時發出提醒,而不是讓生產環境悄悄退回全域直連。

伺服器部署與故障排查:把一次成功變成可維護的方案

在長駐伺服器上,透明代理最怕「重開機後看似服務還在,實際轉送規則已失效」。建議把 Clash 設定、規則提供者清單與 Compose 檔案放進版本控制,敏感資訊則以秘密檔或部署平台的 Secret 管理。每次修改都記錄代理埠、容器網段、DNS 行為與規則版本,日後才能判斷問題是來自節點、核心升級、Docker 網路變更,還是某個 Provider 更新了內容。

四層檢查法

  • 第一層:應用程式。確認 Git、curl、Docker CLI 或套件工具是否真的讀取代理變數。不同工具對大小寫變數、憑證驗證與 SOCKS URL 的支援不一致,不能只用一個工具成功就推論全部正常。
  • 第二層:容器網路。檢查容器的預設閘道、DNS、NO_PROXY 與宿主機代理埠是否可達。若連 host.docker.internal 都無法建立 TCP 連線,規則還沒有機會發揮作用。
  • 第三層:Clash 核心。在連線紀錄中確認入站來源、目的地、DNS 解析結果與最終策略。若完全看不到請求,應回頭查 TUN、策略路由或應用程式是否繞過代理。
  • 第四層:上游服務。確認節點是否支援長連線、大檔下載與目標服務的 TLS。Docker Hub 拉取失敗時,也要分辨是認證端點失敗、Manifest 失敗,還是 Layer 下載中斷。

DNS 失敗通常表現為容器內解析不到域名,或不同時間解析出完全不同的結果;先檢查 DNS 模式與內外網域分流。TCP 連線失敗則多半與監聽位址、防火牆、Docker bridge 或錯誤埠號有關。TLS 握手失敗可能是代理入口類型填錯、系統時間不正確、公司中間人憑證未安裝,或上游節點不適合該服務。只有 Docker Hub 失敗時,不要只加入 docker.io,還要根據連線紀錄觀察認證與 CDN 相關域名,並測試 Registry 的實際 API 端點。

部署在 CI Runner 時,應額外注意建置快取與秘密外洩。不要把帶有代理帳密的完整 URL 印到建置日誌,也不要在 Dockerfile 中用 ARG 永久寫入憑證。可讓 Runner 主機負責透明代理,容器只接觸必要的環境設定;建置完成後清理測試容器,並對外連線設定逾時與重試上限。若團隊成員需要不同出口,應透過策略群組和受控設定檔解決,而不是讓每個人自行修改宿主機防火牆規則。

和只支援單一應用程式環境變數的代理工具相比,Docker 場景最常見的不足是設定分散:一個工具能連線,另一個工具仍然直連;換了容器或重建服務後,代理設定又遺失;遇到 Docker Hub CDN 變更時,也很難知道該補哪個網域。Clash 的優勢在於能把容器入口、DNS 行為、規則提供者與策略群組放進同一套可觀察、可版本化的分流架構,既能為 GitHub 與映像倉庫指定穩定出口,也能讓內網服務維持直連。若你正在尋找適合開發機、CI 或伺服器的統一代理方案,可先從支援你平台的 Clash 用戶端開始建立可驗證的配置。

立即免費下載 Clash,開啟流暢上網新體驗 →