Docker 容器要共用 Clash/Mihomo 的代理出口,關鍵不只是把容器的 DNS 指向代理,而是要讓封包在 Linux 閘道上經過正確的轉送與攔截路徑。本文以 Docker bridge 網路為例,從封包流向、透明代理模式、防火牆規則與策略路由逐步搭建,也會說明 DNS、網段排除及常見逾時問題。實際配置前,請先確認閘道核心使用的是支援相關功能的 Mihomo,並依照發行版選用 iptables 或 nftables;兩套規則管理工具混用時,常會出現規則已加入、實際封包卻沒有命中的情況。
先確認拓撲與封包流向
最容易管理的方式,是讓執行 Docker 的 Linux 主機同時擔任透明閘道:Mihomo 在主機上監聽透明代理連接埠,容器透過 Docker bridge 對外連線,主機防火牆再將符合條件的封包交給 Mihomo。這種做法不需要在每個容器內安裝代理程式,也不必逐一修改應用程式的 HTTP 代理設定。
典型的 IPv4 封包路徑大致如下:
- 容器中的應用程式建立連線,封包從容器的虛擬網卡送到 Docker bridge。
- 封包進入主機的網路堆疊,依目的位址與路由進入轉送路徑。
- 主機的 PREROUTING 規則判斷來源網段、目的網段與協定,將適用的封包重新導向 Mihomo。
- Mihomo 依配置檔中的規則選擇代理、直連或拒絕,並由代理核心建立新的外部連線。
- 回應封包經由連線追蹤與 NAT 狀態返回容器。
另一種拓撲是 Docker 主機與代理閘道分離:容器的預設閘道指向另一台 Linux 路由器,由該路由器執行 Mihomo 與透明代理規則。這種方式適合多台 Docker 主機共用同一出口,但必須確保回程路由也經過閘道,否則連線可能只在去程被攔截,回應卻走了不同路徑。若容器、Docker 主機與閘道之間還有多層 NAT,建議先用單一主機拓撲驗證,再逐步擴展。
172.17.0.0/16。請用 docker network inspect bridge 或檢查自訂網路,確認容器子網、閘道位址與主機上的 bridge 介面名稱;後續規則都應以實際值為準。選擇透明代理模式並準備 Mihomo
常見的透明代理方式有 REDIRECT 與 TPROXY。REDIRECT 透過 NAT 將 TCP 連線導向本機連接埠,設定相對簡單,適合先驗證容器 TCP 流量是否能進入代理核心;但它不保留原始目的位址的方式與 TPROXY 相同,且 UDP 不會因為加入一條 TCP REDIRECT 規則就自動被代理。TPROXY 會保留原始目的位址,通常更適合需要同時處理 TCP、UDP,並希望完整控制透明路由的情境,但需要 mangle 規則與策略路由配合。
若使用 Mihomo 的 TPROXY 監聽埠,設定檔可先加入下列基本項目。代理節點、策略組與規則仍需依自己的訂閱或政策補齊;這段設定只負責開啟透明代理入口,不會自動替你建立 Linux 防火牆規則。
mode: rule allow-lan: true bind-address: "*" tproxy-port: 7893 dns: enable: true listen: 0.0.0.0:1053 enhanced-mode: fake-ip fake-ip-range: 198.18.0.1/16
如果使用 REDIRECT,則應確認所用核心支援相應的透明代理連接埠,並先只處理 TCP。不要把 TPROXY 的策略路由指令直接套用到 REDIRECT,也不要只因為設定了 tproxy-port 就認定 UDP 已經生效。不同 Mihomo 版本、核心能力與防火牆後端可能有差異,部署前應查看啟動日誌,確認監聽連接埠成功建立,並檢查目前生效的規則。
若由 Docker Compose 啟動 Mihomo 容器,而不是直接在主機執行,還要額外處理網路命名空間與權限問題。透明代理核心通常需要操作網路規則或接收轉送流量;僅把代理連接埠映射到主機,未必能讓它攔截主機上的 bridge 流量。此時要明確決定由主機負責攔截、還是讓代理容器加入 host 網路並取得必要能力,不宜同時在兩處建立重複的透明代理規則。
設定防火牆規則與 TPROXY 策略路由
以下示例展示一種常見的 IPv4 TPROXY 思路:只處理 Docker 容器網段中送往外部的 TCP、UDP 封包,先排除區域網路與特殊目的位址,再將封包標記並送入 Mihomo。請將 172.20.0.0/16 換成實際容器網段,並確認閘道內沒有其他服務使用相同的 mark、路由表編號或代理連接埠。
# 將符合條件的封包送到本機路由表 ip rule add fwmark 0x1/0x1 table 100 ip route add local 0.0.0.0/0 dev lo table 100 # 新建專用鏈,避免直接混入既有 Docker 規則 iptables -t mangle -N CLASH_DOCKER 2>/dev/null iptables -t mangle -F CLASH_DOCKER # 排除容器互通、區域網路及非一般單播目的地 iptables -t mangle -A CLASH_DOCKER -d 172.20.0.0/16 -j RETURN iptables -t mangle -A CLASH_DOCKER -d 10.0.0.0/8 -j RETURN iptables -t mangle -A CLASH_DOCKER -d 172.16.0.0/12 -j RETURN iptables -t mangle -A CLASH_DOCKER -d 192.168.0.0/16 -j RETURN iptables -t mangle -A CLASH_DOCKER -d 224.0.0.0/4 -j RETURN iptables -t mangle -A CLASH_DOCKER -d 255.255.255.255/32 -j RETURN # TCP、UDP 分別交由 Mihomo 的 TPROXY 入口處理 iptables -t mangle -A CLASH_DOCKER -p tcp -j TPROXY --on-port 7893 --tproxy-mark 0x1/0x1 iptables -t mangle -A CLASH_DOCKER -p udp -j TPROXY --on-port 7893 --tproxy-mark 0x1/0x1 # 只從 Docker bridge 進入,介面名稱請依環境調整 iptables -t mangle -A PREROUTING -i br+ -s 172.20.0.0/16 -j CLASH_DOCKER
這是說明規則順序的骨架,不應不經檢查就直接套用到正式主機。部分 Docker 與發行版組合會使用 nftables 後端,或以不同方式安排 bridge 流量的處理鏈;若封包沒有經過預期的 PREROUTING 規則,請先查看 iptables -t mangle -nvL 的計數器,再用 nft list ruleset 確認實際後端與鏈順序。計數器始終為零,通常表示介面、來源網段或規則掛接位置不符合真實封包路徑,而不一定是 Mihomo 本身故障。
規則中排除私有網段,是為了避免容器存取宿主機、區域網路服務或其他容器時被誤送到代理。若區域網路中有需要代理的特殊位址,不要直接刪除所有私有網段排除;較安全的做法是縮小排除範圍,或先用具體目的網段設定例外。Docker 的 bridge 規則可能會被 Docker 重啟或網路重建影響,應使用系統服務或防火牆管理工具持久化設定,並確認重載後不會重複建立鏈或重複插入跳轉規則。
使用 REDIRECT 時,處理位置通常改為 NAT 表的 PREROUTING,規則也只應針對 TCP 連線導向對應的 REDIRECT 連接埠。不要把上面的 TPROXY mark 與 ip rule 當成 REDIRECT 必備步驟。無論採用哪一種方式,都要在規則中明確排除 Mihomo 自己的外連流量,以及控制介面、節點伺服器位址和不應代理的管理網段,避免代理核心的出站連線再被送回入口。
處理 Docker DNS 與容器網段排除
Docker bridge 容器常會透過 Docker 提供的內嵌 DNS 解析服務。容器中看到的 /etc/resolv.conf 可能指向 127.0.0.11;這個位址是容器網路命名空間內的解析入口,不等同於主機的 Mihomo DNS 監聽位址。因此,即使 TCP、UDP 透明代理已生效,DNS 仍可能由 Docker 的解析流程代為轉送,不能只憑容器內的 resolver 位址判斷查詢最後走哪個上游。
如果希望容器 DNS 由 Mihomo 處理,可以在 Docker 網路或 Compose 服務中指定可由容器連到的 DNS 位址,例如 Docker 主機在該網段上的 bridge 閘道位址,再讓 Mihomo 在該位址可達的連接埠監聽。不要把 127.0.0.1 當成主機位址填入容器的 DNS 設定:容器中的 loopback 指向容器自己,不是 Docker 主機。設定完成後,先從容器內測試 UDP/TCP 53 的可達性,再從 Mihomo 日誌或 DNS 查詢記錄確認請求確實抵達。
- 保留 Docker 內嵌 DNS 時,先確認 dockerd 的上游 DNS 與主機防火牆路徑,並測試常見域名的解析結果。
- 直接指定 Mihomo DNS 時,確認監聽位址不是只有
127.0.0.1,且防火牆允許容器網段存取指定連接埠。 - 不要不加判斷地把所有 53 埠流量重導到另一個 53 埠入口,否則可能形成 DNS 轉送迴圈,或令 Docker 的服務發現失效。
- 若採用 fake-ip,應確認容器的後續連線會經過同一個 Mihomo 執行個體,讓假 IP 對應表與實際攔截路徑一致。
容器網段排除不只關乎 DNS,也關乎服務互通。容器呼叫宿主機服務、同一 bridge 上的資料庫,或另一個 Docker 網路中的內部服務時,通常應走直連。相反地,容器存取公網位址才依規則送往代理。若自訂 Docker 網路採用多個 CIDR,請逐一檢查;僅排除預設 bridge 網段,無法涵蓋所有 Compose 專案建立的使用者自訂網路。
逐層驗證並排查迴圈與連線逾時
透明代理問題最好由底層往上排查,而不是一開始就反覆更換節點。先確認容器有正確的 IP、預設閘道與 DNS;再確認封包抵達 Linux 主機、對應的防火牆規則計數器增加、策略路由能把標記封包送到本機;最後才檢查 Mihomo 是否收到連線,以及規則選擇的策略組是否可用。
- 檢查 Docker 網路:執行
docker network inspect檢查子網與閘道,在容器內查看路由與解析設定。確認容器沒有被連到預期以外的 Docker 網路。 - 檢查封包是否抵達主機:使用
tcpdump -ni any或指定 bridge 介面觀察容器流量。若封包根本沒到閘道,應先檢查 Docker 路由、網路隔離與上游閘道。 - 檢查防火牆命中:查看 mangle、nat 鏈的封包與位元組計數器。命中數不增加時,優先核對來源 CIDR、介面名稱、協定和鏈的掛接位置。
- 檢查策略路由:使用
ip rule show與ip route show table 100確認規則和 local 路由存在,並核對 mark 遮罩與 TPROXY 規則使用的值一致。 - 檢查 Mihomo:查看核心日誌與連線頁面,確認連線有進入、命中的規則和策略組符合預期。若規則命中但節點無法連線,應轉而檢查節點、DNS 與主機本身的外部連線。
連線逾時常見於回程路徑不一致、核心轉送功能或防火牆轉送政策未放行、容器網段 NAT 與路由衝突,以及節點伺服器位址被錯誤送入透明代理。若所有容器都無法連線,先暫停新增規則並檢查主機的轉送與預設路由;若只有某一類 UDP 應用失敗,則應確認 Mihomo 核心、TPROXY 規則和該應用的 UDP 需求,而不是只測試 TCP 網頁。
迴圈轉送通常可從連線反覆進入同一條防火牆鏈、CPU 使用率異常,或代理核心日誌中反覆出現節點連線建立失敗等現象辨認。常見原因包括代理核心自己的出站封包也被重新攔截、策略路由 mark 過於寬泛、DNS 上游再次指向透明代理入口。排查時先暫時縮小攔截來源,只保留一個測試容器與一個公網目的位址,逐項恢復 DNS、UDP 和其他網段規則,能更快定位是哪條規則造成回流。
調整防火牆前請保存現有規則,並準備主機外部的管理通道或回復方式。特別是遠端操作閘道時,不要一次清空整張防火牆表;建議將自訂規則放在獨立鏈中,驗證成功後再設定持久化。這樣即使配置有誤,也較容易移除自訂鏈,而不會連帶破壞 Docker 自動維護的網路規則。
常見問題
Docker 只映射 Mihomo 的連接埠,容器就會自動走代理嗎?
不會。連接埠映射主要是讓外部或其他網路命名空間連到指定服務,並不等於將容器所有出站封包透明送入代理。要讓容器共用出口,仍需配置容器的代理環境變數,或由主機上的防火牆與策略路由攔截符合條件的流量。
使用 REDIRECT 後,為什麼 UDP 仍然直連或逾時?
常見的 NAT REDIRECT 範例通常只匹配 TCP。UDP 需要核心、代理程式與防火牆規則都有相應支援;若需要保留原始目的位址並處理 UDP,通常應評估 TPROXY,並一併設定 mark、策略路由與回程處理。
容器可以直接把 DNS 設為 127.0.0.1 嗎?
通常不行。容器中的 127.0.0.1 指向容器本身,除非 Mihomo 就在同一個網路命名空間並監聽該位址,否則容器無法透過它連到主機 DNS。請使用容器可達的主機閘道位址,並確認 DNS 監聽與防火牆設定。
防火牆規則計數器是零,應該先改 Mihomo 設定嗎?
不必急著改。計數器為零表示封包可能未經該規則,或來源網段、介面與掛接位置不正確。先用封包擷取工具確認流量實際經過哪個介面與鏈,再檢查 Docker 使用的防火牆後端,通常比盲目更換代理模式更有效。
把 Docker bridge 流量交給 Clash/Mihomo,核心工作是讓每一段封包路徑都能對上:容器網段要辨認正確,防火牆只攔截需要代理的流量,策略路由與 DNS 又不能把封包送回入口。建議先以單一測試容器驗證 TCP,再逐步加入 UDP、DNS 與其他 Docker 網路;確認直連服務、容器互通與代理出口都正常後,再將規則持久化部署。