在 Linux 网关上运行 Clash 或 Mihomo,并不意味着 Docker 容器会自动进入代理。容器访问外网时,流量通常先从 Docker bridge 进入宿主机的转发路径;如果透明代理规则只覆盖宿主机本地进程,或者网段、路由标记与防火墙链没有对齐,容器仍可能直连、DNS 解析异常,甚至出现连接超时。本文从网络拓扑开始,逐步拆解 Docker bridge 流量如何进入 Mihomo 透明代理,并给出策略路由、防火墙、YAML 配置及排障思路。示例使用专用容器网段和独立路由标记,部署时请按实际网卡、网段及防火墙后端调整。
先确认网关拓扑与流量路径
常见部署方式是 Mihomo 运行在 Docker 宿主机上,业务容器连接自定义 bridge 网络。容器访问公网时,数据包从容器虚拟网卡发出,进入宿主机上的 bridge,再经过宿主机的转发和防火墙处理。透明代理规则需要在流量经过的入口拦截它,并把匹配的 TCP 或 UDP 流量交给 Mihomo 的透明代理端口。
一个便于维护的拓扑可以是:
- 业务容器:加入独立的 Docker bridge,例如
172.20.0.0/16,不要与宿主机局域网、VPN 或其他 Docker 网络重叠。 - 宿主机:负责容器网络转发、策略路由与防火墙规则;确认 Docker 使用的 bridge 名称,例如
br-app,实际名称以ip link输出为准。 - Mihomo:在宿主机网络命名空间中监听透明代理端口。这样防火墙可以直接把被截获的流量送到监听端口,不必再处理容器到代理容器的跨网段访问。
- 上游出口:由 Mihomo 的代理节点、策略组和规则决定。容器到宿主机内部服务、局域网设备和需要直连的目标,应在透明代理规则中排除。
排障前先记录实际网段、bridge 名称、Mihomo 监听地址和防火墙类型。可使用 docker network inspect 查看网络子网,用 ip addr 确认 bridge 接口,用 ip route 检查宿主机路由。若 Docker 使用 nftables 后端,手工添加的传统 iptables 规则未必处于预期链路;先确认系统规则实际由哪套工具管理,再选择一致的配置方式。
配置 Mihomo 的透明代理入口
Mihomo 常见透明代理入口包括 redir-port、tproxy-port 等。TCP 重定向方案通常只处理 TCP;如果需要同时接管 UDP,应使用适合当前系统和核心版本的 TPROXY 路径,并确保内核、策略路由与防火墙规则都支持它。端口号只是示例,避免与已有服务监听端口冲突。不同 Mihomo 版本及启动方式对字段支持可能不同,应用配置前应以当前核心文档和启动日志为准。
mixed-port: 7890 allow-lan: true bind-address: '*' # TCP 与 UDP 的透明代理入口;是否启用取决于部署方案 tproxy-port: 7893 mode: rule log-level: info 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
把 DNS 监听在 1053 是为了避免直接占用宿主机常见的 53 端口;这并不会自动让容器使用它。你还需要明确容器 DNS 请求的去向,例如在 Docker 网络或容器配置中指定宿主机 bridge 网关地址,并通过防火墙将发往 DNS 端口的请求转给 Mihomo。若宿主机已有本地解析器,应先决定由哪个服务负责 53 端口,再安排转发或上游关系,避免两个服务争用同一端口。
allow-lan 控制普通代理端口是否接受局域网连接,不等同于启用透明代理,也不是容器透明接管的替代项。透明流量能否进入核心,取决于防火墙是否正确导流;请求最终由哪个策略组处理,则取决于 Mihomo 的规则。可以在规则中明确区分容器访问的局域网地址、直连域名和默认代理出口,避免把网关管理页面等内部服务误送到远端节点。
策略路由与防火墙规则的组合思路
TPROXY 不只是把数据包改写到一个端口。它通常需要给被拦截的数据包设置标记,再通过策略路由把带标记的目标流量视作本地流量,交给本机的透明代理 socket。以下命令展示基本结构,适用于理解机制和构建测试规则,不应不经核对直接复制到生产环境:接口名、容器网段、标记值和链的先后顺序都必须与你的系统一致。
# 为 TPROXY 使用专用标记和路由表编号 ip rule add fwmark 0x1/0x1 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100 # 检查规则是否已生效 ip rule show ip route show table 100
规则标记应尽量使用独立位,避免与现有 VPN、容器网络或 QoS 规则冲突。若主机已经存在基于 mark 的策略路由,不要简单照搬 0x1;应先检查 ip rule show 和防火墙规则中的 mark 掩码,再分配未占用的值。系统重启后规则也需要恢复,可通过发行版的网络配置、systemd 单元或防火墙持久化机制管理,避免只在命令行临时添加。
防火墙处理顺序可以按以下逻辑设计:
- 只匹配指定 bridge 入口和容器源网段,避免接管局域网其他设备或宿主机本地连接。
- 先排除回环、广播、组播、链路本地地址及你的局域网网段;同时排除容器访问宿主机服务和其他容器网段的流量。
- 明确处理 DNS。若容器 DNS 由 Mihomo 接管,就在单独规则中将 TCP/UDP 53 导向指定 DNS 监听端口;若 DNS 交给宿主机解析器,则不要再让透明代理规则意外截获这部分流量。
- 只对剩余、确实要代理的 TCP/UDP 流量设置标记并执行 TPROXY,其他协议按明确的直连或拒绝策略处理。
- 确保代理进程发起的上游连接不会重新命中同一组容器入口规则,防止流量循环进入代理端口。
容器流量进入宿主机的转发路径,不等同于宿主机进程自己发起的本地流量。因此,只有 OUTPUT 链规则通常无法覆盖 Docker bridge 容器;需要检查对应的 PREROUTING 或 nftables 转发处理路径。另一方面,Docker 对发布端口、DNAT 和转发链有自己的规则,规则插入位置错误时,可能影响容器对外发布的服务。建议先用规则计数器和抓包确认数据包实际经过的链,再决定具体挂接点,不要仅凭规则已成功添加就认定流量已被接管。
容器网段排除、回环与 DNS 设计
Docker 环境最常见的透明代理故障,不是代理节点本身不可用,而是内部流量被误拦截,或者代理进程的出口连接再次进入透明代理。排除规则要根据实际拓扑维护,不能只排除一个网段就认为所有内部通信都安全。
- 排除宿主机与局域网目标:将局域网、Docker bridge 网段、VPN 网段和专用管理网段列入直连或防火墙绕过范围。容器访问宿主机网关、内部数据库或其他业务容器时,应沿原有网络路径通信。
- 避免代理出口回环:透明代理接管的是进入宿主机的客户端连接;Mihomo 再向节点服务器建立的上游连接必须能够正常出站。根据部署方式,可通过进程标记、独立出口路由或明确排除上游节点地址来避免再次拦截。使用用户 ID 排除时,先确认核心实际运行用户及防火墙匹配条件。
- 区分 DNS 的实际发起者:Docker 内置 DNS 通常由容器访问本地解析地址,再由 Docker 服务转发查询。宿主机看到的上游 DNS 请求未必仍以原容器地址出现,因此不能假设只匹配容器源地址就能接管所有 DNS。通过容器内解析测试和宿主机抓包确认请求经过的环节。
- 检查 fake-ip 的适用范围:使用 fake-ip 时,应用连接到的是虚拟地址,透明代理核心需要能够将地址映射回域名。容器或应用若使用自带 DNS、固定 IP、DoH,或者缓存了旧解析结果,可能绕过预期解析路径。必要时针对内部域名配置排除,避免内网服务被虚拟地址影响。
- 为容器网络保留独立地址段:如果容器网段与家庭路由器、办公网或远程代理网络重叠,路由选择会变得不确定。改用不冲突的自定义子网,并检查主机上的路由表,比增加更多防火墙例外更可靠。
DNS 方案建议先选定一个明确的责任边界:要么让容器直接使用宿主机上可达的 Mihomo DNS 监听地址,要么让宿主机解析器作为前端再转发给 Mihomo 或指定上游。不要让容器、Docker daemon、宿主机解析器和 Mihomo 同时各自做一套不透明的转发。测试时分别执行域名解析与 IP 直连:域名解析失败通常指向 DNS 路径;IP 也无法连接则要继续检查转发、路由、代理监听和节点可达性。
连接超时排障与常见问题
排查时按“容器出口—宿主机入口—路由标记—Mihomo 连接—DNS”逐层确认,比反复更换节点更有效。可在容器内用 curl 或 nc 测试目标,用 tcpdump 在 bridge 接口观察数据包;在宿主机检查策略路由和防火墙计数器,并查看 Mihomo 日志与连接记录。若规则命中而 Mihomo 没有连接,重点检查 TPROXY 监听端口、策略路由表和 mark;若 Mihomo 已有连接但请求超时,再检查代理组、规则匹配、上游节点与返回路径。
容器能访问 IP,但域名访问失败,先查什么?
优先检查容器实际使用的 DNS 服务器、DNS 请求是否到达宿主机,以及 53 端口是否由预期服务接收。确认 Mihomo 的 DNS 监听地址能从容器网段访问,再检查容器是否启用了自带 DoH 或缓存了旧解析。不要只根据宿主机上执行解析成功,就推断容器使用了同一条 DNS 路径。
防火墙计数器增长了,但连接仍然超时怎么办?
计数增长只表示规则匹配,不代表流量已被正确送入核心。确认 TPROXY 端口与 Mihomo 实际监听端口一致,检查 fwmark 是否与 ip rule 匹配、路由表中是否存在本地路由,并确认规则没有被后续链提前返回或覆盖。再查看 Mihomo 日志判断连接是否到达,以及是否卡在代理节点连接或目标站点访问阶段。
为什么宿主机可以代理,容器却不能?
宿主机程序发起的流量通常经过本地输出路径,而 Docker 容器流量从 bridge 进入宿主机转发路径,两者经过的防火墙链可能不同。检查是否只配置了本地流量规则、是否选错 bridge 接口、是否漏掉容器源网段,以及 Docker 与系统防火墙是否使用不同后端。
TCP 正常但 UDP 不通,是否代表整个代理配置失败?
不一定。TCP 重定向规则可能已经工作,但 UDP 需要独立的透明代理支持、TPROXY 规则与策略路由,同时还受核心配置、节点协议和网络出口限制。先确认 Mihomo 是否收到 UDP 连接,再用单一目标测试;如果业务并不需要 UDP,也可以明确限制或直连,而不是盲目增加宽泛规则。
Docker 透明代理的关键,是让拓扑、入口匹配、策略路由、DNS 和排除范围保持一致。先用单一 bridge 与测试容器验证,再把规则纳入持久化配置和变更记录;当网段、Docker 后端或 Mihomo 版本变化时,按同一套检查顺序复测。这样比堆叠临时防火墙命令更容易定位故障,也更适合长期维护容器的统一代理出口。