把 Clash 放進 Docker,不只是把設定檔掛載進容器這麼簡單。容器擁有獨立的網路命名空間,程式送出的封包通常會先經過 Docker bridge、主機 NAT 與容器自身的路由表;如果沒有正確安排轉發、DNS 與代理接管方式,常見結果就是「宿主機可以連線,容器卻下載逾時」,或是瀏覽器能走代理,但套件管理器仍然直接連到錯誤的 IP。本文從封包流向開始,示範如何在 Docker 中部署 Mihomo/Clash,建立適合程式開發、套件下載與服務測試的透明代理環境。

Docker 透明代理的工作原理

一般 Docker 容器會透過 docker0 bridge 取得私有 IP,例如 172.17.0.2。容器發出的請求先送到預設閘道 172.17.0.1,再由主機進行 SNAT,最後從主機的實體網卡或 VPN 介面離開。若只在宿主機上啟動 Clash 的 HTTP 或 SOCKS5 代理,容器不會自動使用它,因為容器內的應用程式通常不知道主機代理位址。

透明代理的概念,是在應用程式不需要設定代理的前提下,由核心防火牆規則攔截流量,再將封包交給 Clash 處理。依照部署方式,可以分成三個層次:

  • 環境變數代理:在容器中設定 HTTP_PROXY、HTTPS_PROXY 與 ALL_PROXY。設定最簡單,但只對支援代理的程式有效,部分 Git、DNS、套件管理器或自訂 TCP 程式可能不會遵守。
  • 宿主機轉發:讓容器流量先通過主機,再由主機的 nftables、iptables 或 TPROXY 規則送入 Clash。這是較常見的透明代理架構,但需要處理來源地址、回程路由與防火牆權限。
  • Host 網路模式:讓 Clash 容器直接使用宿主機的網路命名空間。部署簡單、效能較好,但隔離性降低,且連接埠容易與主機其他服務衝突。

如果目標只是讓少數開發容器下載套件,環境變數或在應用程式內設定 HTTP 代理通常已經足夠。若需要接管不支援代理設定的二進位程式、容器內 DNS 請求,或希望所有出站 TCP/UDP 流量都遵守 Clash 規則,才適合採用透明代理。

先確認核心能力:不同 Clash 分支對 TUN、TPROXY、redir-host 與 UDP 透明轉發的支援程度不完全相同。2026 年的新部署建議優先使用 Mihomo,並在啟動前確認主機核心已載入 tun、nf_tproxy_ipv4 或對應 nftables 模組。

使用 Docker Compose 部署 Mihomo

先建立專用目錄,例如 /opt/mihomo,將設定檔命名為 config.yaml。以下 Compose 範例使用 Host 網路模式,適合把 Clash 當作主機級代理服務;NET_ADMIN 用於建立 TUN 介面,SYS_MODULE 則方便容器載入部分核心模組。若主機已經具備所需模組,可以移除不必要的權限。

docker-compose.yml
services:
  mihomo:
    image: metacubex/mihomo:latest
    container_name: mihomo
    restart: unless-stopped
    network_mode: host
    cap_add:
      - NET_ADMIN
      - NET_RAW
    devices:
      - /dev/net/tun:/dev/net/tun
    volumes:
      - ./config.yaml:/root/.config/mihomo/config.yaml:ro
      - ./rules:/root/.config/mihomo/rules
    environment:
      TZ: Asia/Taipei

啟動前先確認主機存在 TUN 裝置:

建立 TUN 裝置並啟動服務
sudo modprobe tun
ls -l /dev/net/tun
docker compose up -d
docker compose logs -f mihomo

如果主機沒有 /dev/net/tun,不要直接把問題歸咎於 YAML。部分雲端主機或受限虛擬化環境不允許建立 TUN,這時可以改用 redir 端口、HTTP/SOCKS5 代理,或改在具備完整核心權限的主機上運行。使用 network_mode: host 時,Compose 的 ports 欄位不再生效,Clash 的監聽地址與埠號會直接佔用主機資源。

YAML 中的 TUN、DNS 與分流設定

透明代理的設定核心通常是 tun、dns 與 rules。TUN 會在主機建立虛擬網卡,將 IP 流量交給 Mihomo;DNS 使用 fake-ip 可以讓 Clash 在還沒有取得真實 IP 之前,就依照域名規則決定代理或直連。對開發環境而言,這種方式特別適合 GitHub、容器映像倉庫、語言套件來源與 API 服務混合使用的情境。

Docker 主機適用的 TUN 與 DNS 配置
mixed-port: 7890
allow-lan: true
bind-address: '*'
mode: rule
log-level: info

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

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
  fallback-filter:
    geoip: true
    geoip-code: CN

rules:
  - DOMAIN-SUFFIX,github.com,PROXY
  - DOMAIN-SUFFIX,githubusercontent.com,PROXY
  - DOMAIN-SUFFIX,docker.io,PROXY
  - DOMAIN-SUFFIX,npmjs.org,PROXY
  - DOMAIN-SUFFIX,pypi.org,PROXY
  - DOMAIN-SUFFIX,openai.com,PROXY
  - GEOIP,LAN,DIRECT
  - GEOIP,CN,DIRECT
  - MATCH,PROXY

auto-route 會嘗試把主機路由導向 TUN,auto-detect-interface 則讓 Mihomo 自動判斷實際出站介面。若主機同時有有線網卡、Wi-Fi 與 VPN,建議先查看啟動日誌,確認自動選出的介面正確。dns-hijack 用於攔截 53 埠 DNS 請求,但它不一定能接管所有 DoH、DoT 或應用程式內建 DNS,因此仍應在必要時額外設定應用程式的解析策略。

規則順序也十分重要。Clash 會由上往下匹配,先放入內網直連、公司網域或本地服務,再處理需要代理的套件來源,最後使用 MATCH 作為兜底。若把 GEOIP,CN,DIRECT 放在 GitHub 或套件來源之前,可能因為 CDN IP 被判定為中國 IP 而錯誤直連,所以對需要穩定代理的域名,應將明確的 DOMAIN-SUFFIX 規則放在前面。

容器流量轉發與環境變數方案

使用 Host 網路模式時,TUN 通常可以直接接管宿主機及其部分轉發流量;但 Docker bridge、使用自訂網路的容器,以及啟用了特殊網路策略的服務,仍可能需要額外檢查。先在容器內查看預設路由與 DNS:

檢查容器的路由與 DNS
docker run --rm alpine ip route
docker run --rm alpine cat /etc/resolv.conf
docker exec -it your-app sh
ip route
getent hosts github.com
wget -S -O- https://github.com

如果不需要完整透明代理,也可以讓應用容器明確使用 Clash 的 mixed port。由於容器中的 127.0.0.1 指向容器自身,不能直接寫成 127.0.0.1:7890;應使用 Docker gateway、主機區域網路 IP,或 Compose 建立的服務名稱。

讓開發容器使用 Clash mixed port
services:
  builder:
    image: node:22
    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,.local,172.16.0.0/12
    extra_hosts:
      - "host.docker.internal:host-gateway"

NO_PROXY 是容易被忽略的欄位。內部資料庫、服務發現名稱、容器網段與本機健康檢查通常不應經過外部代理,否則可能出現連線變慢、來源 IP 不符,甚至代理伺服器無法解析內部服務名稱的問題。不同程式對 HTTP_PROXY 大小寫的支援也不完全一致,實務上可以同時設定大小寫版本。

若使用 bridge 模式搭配獨立的 Clash 容器,兩者必須加入同一個 Docker network,並讓 Clash 監聽 0.0.0.0。但這只代表應用程式可以連到 HTTP/SOCKS5 埠,不等於已經完成透明代理。要攔截任意 TCP/UDP 流量,仍需共享網路命名空間、使用 TUN,或在主機層配置 nftables/TPROXY。

面向開發工作的 YAML 進階分流

開發環境不適合只使用「全部代理」或「全部直連」兩種極端策略。更穩定的做法是先分類:程式碼託管與映像倉庫通常需要代理;區域套件鏡像、公司內網與區域網路服務應直連;無法明確判定的流量再交給預設策略組。這樣能減少不必要的延遲,也避免內網服務因代理路徑而失效。

開發用途的策略組與規則片段
proxy-groups:
  - name: PROXY
    type: select
    proxies:
      - 自動選優
      - DIRECT

  - name: 自動選優
    type: url-test
    include-all: true
    url: https://www.gstatic.com/generate_204
    interval: 300
    tolerance: 80

rules:
  - DOMAIN-SUFFIX,registry.npmjs.org,PROXY
  - DOMAIN-SUFFIX,pypi.org,PROXY
  - DOMAIN-SUFFIX,repo.maven.apache.org,PROXY
  - DOMAIN-SUFFIX,ghcr.io,PROXY
  - DOMAIN-SUFFIX,registry-1.docker.io,PROXY
  - DOMAIN-SUFFIX,company.internal,DIRECT
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - MATCH,PROXY

容器映像下載還有一個容易混淆的地方:執行 docker pull 的是 Docker daemon,不是目前的 shell。即使你的終端機設定了代理,Docker daemon 仍可能完全不知道代理存在。若 Docker Hub 或其他 registry 無法連線,應在 daemon 層設定代理,或配置 registry mirror;不要只修改應用容器的環境變數。

另一方面,git、npm、pip 與 cargo 對代理的行為各不相同。Git 可能使用自己的 http.proxy,npm 會讀取 npm 設定,pip 則常依賴環境變數。如果透明代理已經正常接管,建議不要同時在每個工具內設定不同代理,否則容易產生重複代理、認證錯誤或 NO_PROXY 不一致的問題。

實務建議:先用一個測試容器驗證域名解析與 HTTPS,再逐一測試 Git、套件管理器和 Docker registry。每次只改動一個變數,並從 Clash Dashboard 的 Connections 頁面確認實際命中的規則與策略組,排查速度會比反覆重啟服務快很多。

常見問題與系統化排查方法

當容器無法連線時,建議按照「應用程式 → 容器網路 → 主機路由 → Clash」的順序排查,而不是一開始就修改大量 YAML。首先確認容器是否能解析域名,接著確認能否連到 Clash 的代理埠,再觀察 Clash 是否收到連線。

現象常見原因檢查方向
容器 DNS 逾時DNS 被錯誤導向、fake-ip 網段衝突或 53 埠未被接管查看 /etc/resolv.conf、測試 getent hosts,並檢查 DNS 監聽埠
宿主機可用,容器不可用Docker bridge 流量未進入 TUN 或主機未開啟 IP forwarding檢查 sysctl net.ipv4.ip_forward、路由表與 nftables 計數器
GitHub 可開但 npm 逾時npm 使用不同 registry,或規則只覆蓋主站域名查看實際 registry URL,再補上對應的 DOMAIN-SUFFIX 規則
Docker pull 仍然失敗Docker daemon 沒有使用代理檢查 daemon 的 systemd proxy 設定與重啟狀態
部分服務不斷重連UDP 未被 TUN 接管、MTU 太大或 fake-ip 不相容暫時排除 fake-ip、調低 MTU,並確認服務是否依賴 UDP

遇到「規則未命中」時,先看 Connections 中顯示的目標是域名還是 IP。如果應用程式直接連 IP,域名規則自然不會生效,這時需要補充 IP-CIDR、啟用 no-resolve,或讓應用程式改用域名連線。若看到目標是 198.18.x.x,代表請求已進入 fake-ip,應回頭確認 fake-ip 對映與 DNS 劫持是否正常。

安全性方面,不要在沒有必要時把 External Controller 綁定到公網或區域網路。若需要 Dashboard,建議只監聽 127.0.0.1,或至少設定高強度 secret、限制防火牆來源。對外開放 mixed-port 也同樣危險,因為未授權使用者可能利用你的主機轉發流量。

完成部署後,可以用一個最小測試清單驗收:容器能解析內網域名;區域網路服務保持直連;指定的 GitHub 或套件來源命中代理;停止代理節點後,策略組能按預期切換;主機重啟後 Docker 與 TUN 能自動恢復。這些測試比單純確認 Dashboard 顯示「執行中」更能證明透明代理真的生效。

Docker 化的 Clash 讓代理配置與應用環境分離,既方便版本管理,也能讓多個開發專案共用同一套分流規則。建議先從 HTTP/SOCKS5 或環境變數方案開始,確認域名、路由與規則邏輯後,再啟用 TUN 和 DNS 劫持。當容器網路、主機核心能力與 YAML 三者配合正確,套件下載、映像拉取及跨境 API 呼叫就能在不修改每個應用程式的情況下穩定運作。

立即開始

用 Clash 掌控您的流量

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

免費下載 查看設定指南 →