在 Docker 環境中,主機上的 Clash 明明可以正常開啟 GitHub、Docker Hub 或 AI 服務,但容器內的 git clone、套件安裝與 API 請求卻經常逾時,這是非常常見的網路配置問題。原因通常不在節點本身,而在於容器擁有獨立的網路命名空間:主機上的代理監聽位址、DNS 解析結果、路由規則與容器並不一定能直接共用。

要讓 Docker 容器穩定經過 Clash,需要先分清楚三種方案:在應用程式中設定 HTTP/SOCKS5 代理、使用 Docker 網路直接連到主機代理埠,以及透過 TUN、iptables 或 REDIRECT 實現透明代理。本文以 Linux 主機上的 Clash 或 Mihomo 為例,說明容器網路、DNS、透明攔截與代理環境變數的完整配置,並針對 GitHub、Docker Registry、npm、pip、Go Modules 及 AI API 等常見場景給出可直接修改的範例。

先理解 Docker 容器為何連不上外部服務

Docker 預設使用 bridge 網路。容器會獲得一個獨立的私有 IP,例如 172.17.0.2,再透過主機上的虛擬網橋和 NAT 存取外部網路。此時容器中的 127.0.0.1 指向容器自己,而不是主機。也就是說,即使 Clash 正在主機的 127.0.0.1:7890 提供 HTTP 代理,容器訪問相同位址時,實際上訪問的是容器內部的 7890 埠,通常自然會得到 connection refused。

另外,Docker 會替容器產生自己的 /etc/resolv.conf,DNS 請求可能由 Docker 內建的 DNS 轉發器處理。如果 Clash 使用 fake-ip 或自訂 DNS,而容器仍直接使用主機或區域網路 DNS,就可能出現以下現象:

  • GitHub 網域解析到錯誤或無法連線的 IP,導致 git clone 長時間停留在 Connecting。
  • Docker Hub 的登入端點可以開啟,但映像檔分層下載失敗。
  • pip installnpm installgo mod download 在某些套件網域上逾時。
  • AI SDK 能解析 API 網域,卻在 TLS 握手或串流回應階段中斷。
  • 容器內設定了代理變數,但 HTTPS 請求仍然直連,或因 NO_PROXY 寫法錯誤而繞過代理。

因此,排查時不要只測試主機瀏覽器。應分別驗證「容器能否連到主機代理埠」「容器 DNS 是否正確」「應用程式是否讀取代理變數」以及「Clash 規則是否命中」。這四個環節中任何一個出錯,都可能被誤判為節點不可用。

讓 Clash 正確監聽 Docker 可訪問的位址

第一步是修改 Clash 或 Mihomo 的代理監聽設定。若 mixed-porthttp-portsocks-port 只綁定在 127.0.0.1,Docker bridge 內的容器無法從主機外部介面存取。對於需要讓容器使用代理的主機,通常應讓代理監聽 0.0.0.0,再透過主機防火牆限制可訪問來源。

Clash/Mihomo 監聽設定
mixed-port: 7890
allow-lan: true
bind-address: '*'

# 若分開提供 HTTP 與 SOCKS5,可使用以下設定
port: 7891
socks-port: 7892

# 建議設定存取控制,避免代理埠暴露到不可信網路
authentication:
  - docker-user:strong-password

mixed-port 可以同時接受 HTTP 代理與 SOCKS5 請求,對大多數命令列工具而言較容易維護。若你的版本不支援 mixed port,則要根據應用程式需求選擇 http-portsocks-port。修改後請從容器內測試主機代理位址,而不是直接假設設定已生效。

在 Linux Docker bridge 網路中,主機通常可以透過 172.17.0.1 被容器訪問,但不同發行版、Docker 網路或自訂 bridge 的閘道位址可能不同。更穩定的做法是在 Compose 中建立主機別名:

docker-compose.yml 主機別名
services:
  worker:
    image: alpine:latest
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      HTTP_PROXY: http://host.docker.internal:7890
      HTTPS_PROXY: http://host.docker.internal:7890
      ALL_PROXY: socks5://host.docker.internal:7890
      NO_PROXY: localhost,127.0.0.1,::1,.local
安全提醒:將 Clash 綁定到 0.0.0.0 後,代理埠可能被區域網路其他裝置使用。請設定 authentication,並在主機防火牆中只允許 Docker 網段或可信內網存取,切勿將 7890 埠直接暴露到公網。

動手配置:讓容器使用代理完成 GitHub 請求

下面以一個臨時 Alpine 容器作為測試,先確認主機名稱解析、代理埠連通性與 HTTPS 請求是否正常。Alpine 預設工具較少,實際排查時也可以使用包含 curldiggetent 的 Debian、Ubuntu 映像檔。

  1. 先在主機上確認 Clash 正在監聽:使用 ss -lntp | grep 7890,確保不是只監聽 127.0.0.1:7890
  2. 啟動測試容器,並將主機映射為 host.docker.internal
  3. 在容器內用 nccurl 測試主機代理埠是否能建立 TCP 連線。
  4. 設定 HTTP_PROXYHTTPS_PROXY,再以 curl 測試 GitHub 或其他目標服務。
  5. 最後再把相同環境變數放入正式服務的 Compose 設定,避免只在互動式 Shell 中暫時有效。
容器內的連通性測試
docker run --rm -it \
  --add-host=host.docker.internal:host-gateway \
  alpine:latest sh

# 容器內執行
apk add --no-cache curl bind-tools
getent hosts host.docker.internal
nc -vz host.docker.internal 7890

export HTTP_PROXY=http://host.docker.internal:7890
export HTTPS_PROXY=http://host.docker.internal:7890
export ALL_PROXY=socks5://host.docker.internal:7890
export NO_PROXY=localhost,127.0.0.1,::1,.local

curl -I https://github.com
curl -I https://registry-1.docker.io

如果 nc -vz 失敗,問題仍在 Docker 到主機的網路路徑,與 GitHub 或節點無關。若埠可以連通但 curl 失敗,請檢查 Clash 日誌是否出現請求,以及請求使用的協議是否正確。HTTP 代理應使用 http://host:7890;即使目標網址是 HTTPS,HTTP CONNECT 仍由 HTTP 代理埠處理,不應擅自寫成 https://

對於 Git,除了環境變數,也可以明確設定 Git 代理。這對某些不會自動繼承 Shell 變數的 CI Runner 特別有用:

Git 與套件工具代理設定
git config --global http.proxy http://host.docker.internal:7890
git config --global https.proxy http://host.docker.internal:7890

# pip
pip config set global.proxy http://host.docker.internal:7890

# npm
npm config set proxy http://host.docker.internal:7890
npm config set https-proxy http://host.docker.internal:7890

# Go 通常使用環境變數控制模組下載
export GOPROXY=https://proxy.golang.org,direct

DNS 與透明代理:不依賴應用程式設定

環境變數方案簡單、可控,卻有一個限制:只有支援代理的應用程式才會使用它。部分二進位程式、第三方 SDK、容器內的背景服務或硬編碼連線程式可能完全忽略 HTTP_PROXY。如果需要讓未修改的程式也能被代理,就要考慮 TUN 或 REDIRECT 透明代理。

在使用 fake-ip 時,DNS 尤其重要。應用程式先向 DNS 詢問網域,再使用得到的 IP 建立連線;若容器拿到真實但被污染的 IP,Clash 可能無法依網域規則正確判斷。Mihomo 的 TUN 模式通常搭配 fake-ip,讓 DNS 查詢與連線攔截都由代理核心統一處理。

Mihomo TUN 與 DNS 基礎範例
dns:
  enable: true
  listen: 0.0.0.0:1053
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  nameserver:
    - 223.5.5.5
    - 119.29.29.29
  fallback:
    - tls://1.1.1.1:853
    - tls://8.8.8.8:853

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true

Docker 容器若要直接使用主機的 TUN 透明代理,通常需要共享主機網路或授予 NET_ADMIN、掛載 /dev/net/tun 等權限。這會增加容器權限與故障排查複雜度,除非你要代理大量不支援環境變數的程式,否則優先推薦「Clash 在主機監聽 + 容器設定代理變數」的方式。

若使用 network_mode: host,容器會直接共用主機網路命名空間,因此可以使用 127.0.0.1:7890,但也會失去 Docker 網路隔離,而且只適用於 Linux。對生產服務而言,應先評估埠衝突、服務暴露面與權限需求,不要為了省去一個主機別名就全面改用 host network。

代理環境變數、NO_PROXY 與 Clash 規則最佳實踐

HTTP_PROXYHTTPS_PROXY 與小寫版本的環境變數並沒有完全一致的相容性。部分 Linux 工具只讀取大寫,部分函式庫則優先讀取小寫。Compose 中建議兩種大小寫都設定,避免不同語言的 HTTP 客戶端行為不一致。

推薦的 Compose 代理環境變數
environment:
  HTTP_PROXY: http://host.docker.internal:7890
  HTTPS_PROXY: http://host.docker.internal:7890
  ALL_PROXY: socks5://host.docker.internal:7890
  http_proxy: http://host.docker.internal:7890
  https_proxy: http://host.docker.internal:7890
  all_proxy: socks5://host.docker.internal:7890
  NO_PROXY: localhost,127.0.0.1,::1,host.docker.internal,.local,172.17.0.0/16
  no_proxy: localhost,127.0.0.1,::1,host.docker.internal,.local,172.17.0.0/16

NO_PROXY 的內容要依實際服務調整。資料庫、Docker 內部 API、服務發現網域與主機別名通常不應繞到外部代理;但如果把 github.comopenai.comdocker.io 放入排除清單,相關請求就會直接連線,容易再次出現逾時。部分程式對 CIDR 格式的支援不完整,因此遇到排除規則無效時,可先改用明確主機名稱或 IP 逐項測試。

Clash 規則則應把 GitHub、Docker Hub 和 AI 服務放在足夠早的位置,避免先被通用的 GEOIP、MATCH 或錯誤的直連規則截走。常見的規則順序如下:

  • 區域網路、主機名稱與內部服務先走 DIRECT
  • GitHub、GitLab、Docker Registry、套件註冊庫與 AI API 網域交給代理策略組。
  • 中國大陸常用服務依需求直連,避免所有流量都繞行代理。
  • 最後才使用 GEOIP,CN,DIRECTMATCH,Proxy 作為兜底。
容器常用目標的規則範例
rules:
  - DOMAIN-SUFFIX,github.com,Proxy
  - DOMAIN-SUFFIX,githubusercontent.com,Proxy
  - DOMAIN-SUFFIX,docker.io,Proxy
  - DOMAIN-SUFFIX,docker.com,Proxy
  - DOMAIN-SUFFIX,openai.com,Proxy
  - DOMAIN-SUFFIX,anthropic.com,Proxy
  - DOMAIN-SUFFIX,pypi.org,Proxy
  - DOMAIN-SUFFIX,npmjs.org,Proxy
  - DOMAIN-SUFFIX,golang.org,Proxy
  - GEOIP,CN,DIRECT
  - MATCH,Proxy

常見故障的定位順序

當容器仍然連不上 GitHub 或 AI 服務時,建議按照由近到遠的順序檢查,而不是立即更換節點。首先確認容器內的 host.docker.internal 是否能解析,再確認 7890 埠是否可連線;接著檢查環境變數是否存在,並使用 curl 的 -v 觀察是否建立了 HTTP CONNECT。若代理埠有請求但目標失敗,再查看 Clash 的連線記錄與規則命中結果。

  • Connection refused:通常表示 Clash 只監聽 localhost、埠號填錯,或主機防火牆拒絕了 Docker 網段。
  • Could not resolve host:先檢查容器 DNS、NO_PROXY 與 fake-ip 配置,不要只更換代理節點。
  • 407 Proxy Authentication Required:Clash 開啟了認證,但代理 URL 沒有加入使用者名稱與密碼。
  • TLS handshake timeout:可能是目標被直連、DNS 污染、MTU 問題或代理節點對該服務不穩定。
  • Git 可以使用但 Docker pull 失敗:Docker daemon 的代理設定與容器環境變數是兩個不同層級,需要另外配置 daemon。

特別要注意,執行 docker pull 的是 Docker daemon,不是你啟動的應用程式容器。因此即使 Compose 裡的服務已設定代理,Docker Engine 本身仍可能無法訪問 Docker Hub。若需要讓 daemon 走代理,應依系統的 systemd drop-in 設定 HTTP_PROXYHTTPS_PROXY,更新後執行 daemon reload 和 restart,再使用 docker info 確認代理欄位。

實務建議:先用顯式代理變數完成配置,再考慮 TUN 或 iptables 透明攔截。顯式代理的流量邊界清楚、權限要求低,也比較容易從 Clash Dashboard 觀察;只有在應用程式無法修改、服務數量很多或需要全流量接管時,才值得引入透明代理。

完成以上設定後,Docker 容器就能以可控、可追蹤的方式存取 GitHub、Docker Hub、套件註冊庫與 AI 服務。實際部署時,請將代理位址、認證資訊與 NO_PROXY 清單放入安全的環境管理機制,不要把私密節點資訊直接提交到 Git 儲存庫。先驗證 DNS,再驗證代理埠,最後確認 Clash 規則命中,通常能快速定位大部分容器代理問題。

立即開始

用 Clash 掌控您的流量

支援 Windows、macOS、Linux、Android 與 iOS,靈活規則,開箱即用。

免費下載 查看設定指南 →