背景
一份 mihomo 配置往往同时包含代理节点、自动测速、故障转移、域名分流和兜底规则。配置规模较小时,把这些内容理解成一张“代理列表”似乎也能工作;但节点和规则逐渐增多后,常见问题就会出现:换一个节点为什么要改多处配置?规则已经命中,为什么最终走的不是预期节点?自动选择与手工选择之间又是什么关系?
mihomo 通过 proxies、proxy-groups 和 rules 把这些问题拆成三个职责明确的层次。理解这三层,不仅有助于编写配置,也能让节点维护、策略调整和分流排障变得更可预测。
mihomo 三层设计结论
mihomo 的核心配置可以概括为“能力、策略、决策”三层:
proxies对应“能力池/节点池”,很像 Nginx 的upstream成员。proxy-groups对应“策略层/调度层”,类似“对 upstream 的策略封装(手选、自动优选、故障转移、负载)”。rules对应“路由决策层”,类似“按条件把请求分流到不同策略”。
但有一个关键差异:mihomo 更偏“连接/流量元数据路由”(L3/L4 + 域名语义),Nginx 更偏“HTTP 请求语义路由”(L7)。
从一次实际连接的执行顺序看,则是:rules 先决定使用哪个策略,proxy-groups 再选出具体出站,最后由 proxies 中的节点完成连接。可以把它记成一句话:规则决定方向,组决定策略,节点决定怎么连接。
图表源文件
下列图表的可编辑 Draw.io 源文件为
Draws/mihomo-three-layer-config-design.drawio,其中包含“三层职责关系”和“单次连接决策流程”两个页面;文章使用同源导出的 SVG。
图 1:mihomo 三层职责关系。主路径是“流量元数据 → rules → proxy-groups → proxies”,规则也可以直接返回内置动作。
三个字段分别解决什么问题
| 字段 | 关注点 | 典型内容 | 设计目标 |
|---|---|---|---|
proxies | 单个出站如何连出去 | 协议类型、地址、端口、认证、TLS/Reality/Hysteria 参数 | 把“节点细节”与“策略逻辑”解耦 |
proxy-groups | 多个出站怎么选 | select/url-test/fallback/load-balance 等策略 | 把“策略变化”与“节点定义”解耦 |
rules | 什么流量走什么策略 | DOMAIN/IP-CIDR/GEOIP/RULE-SET 等规则 | 把“业务路由”与“出站实现”解耦 |
这三个层次拆开后,配置演进更稳定:
- 换节点,通常只改
proxies。 - 改选路逻辑,通常只改
proxy-groups。 - 改业务分流,通常只改
rules。
一次连接如何经过这三层
以 mode: rule 为前提,典型执行链路如下:
图 2:单次连接的运行时决策流程。规则可以直接执行动作、直接指向节点,或先进入策略组再解析到最终节点。
入站接收连接
- 来源可能是
mixed-port、redir、tproxy、tun。
- 来源可能是
生成流量元数据(metadata)
- 目的地址(域名/IP)、端口、协议(TCP/UDP)等。
- 若启用 DNS
fake-ip,会先通过映射把 fake-ip 还原到域名语义。 - 若启用流量嗅探(sniffer),可从 TLS SNI / HTTP Host 补全域名信息。
规则引擎顺序匹配
rules- 自上而下,first-match-wins(命中即停止)。
- 规则结果是一个“动作或目标”:
DIRECT/REJECT/ 某个proxy-group/ 某个proxy。
若目标是
proxy-group,进入组策略决策select:使用当前手工选择项。url-test:按探测延迟选择更优节点。fallback:优先主节点,不可用时自动切换。load-balance:按策略分摊连接(版本相关)。
解析到最终
proxy- 确定一个具体节点后,由对应协议适配器发起握手与转发。
管理连接生命周期
- 已建立连接通常不会因规则变更而立即迁移;新连接按新规则生效。
这就是三层设计在运行时形成的完整闭环。
与三层设计密切相关的字段
proxy-providers
作用:把节点来源外部化(订阅/API/文件),避免在 proxies 手工维护大量节点。
设计价值:
- 数据与策略分离:节点集合可动态更新,
proxy-groups只引用集合。 - 降低变更成本:节点轮换不需要改规则层。
rule-providers
作用:把规则集外部化,rules 里通过 RULE-SET,<name>,<target> 引用。
设计价值:
- 规则可复用、可更新。
- 主配置更短,业务规则与基础规则分层。
mode
rule:走规则引擎(最常用)。global:忽略规则,强制走一个全局策略。direct:忽略规则,全部直连。
设计价值:用模式切换实现“故障旁路”和“排障开关”。
dns.respect-rules
作用:让 DNS 查询的出站路径也受规则/策略影响,减少“请求走代理但 DNS 直连”造成的策略不一致。
设计价值:统一控制平面,降低 DNS 泄漏和分流错位。
rules 中的 no-resolve
典型写法:IP-CIDR,1.1.1.1/32,Proxy,no-resolve
作用:命中 IP 规则时不再触发额外解析流程。
设计价值:
- 提升匹配效率。
- 避免某些场景下的二次解析副作用。
sniffer、tun 与 dns.fake-ip
它们不直接属于三字段,但直接影响 rules 可见的元数据质量:
sniffer提升域名识别能力。dns.fake-ip让“先 DNS 后连接”的流量仍可按域名规则分流。tun决定透明代理路径与流量进入方式。
换句话说:这几项是规则引擎的“数据供给层”。
与 Nginx 的对应关系和关键差异
| 维度 | mihomo | Nginx |
|---|---|---|
| 资源池 | proxies | upstream 服务器列表 |
| 策略层 | proxy-groups | upstream 负载策略/backup/failover |
| 路由层 | rules | location/map/条件路由 |
| 主要决策对象 | 连接元数据(域名/IP/端口/协议/进程等) | HTTP 请求语义(Host/URI/Header 等) |
| 生效粒度 | 更偏“连接级” | 更偏“请求级” |
| DNS 参与度 | 很高(fake-ip、规则感知 DNS) | 通常较低(反向代理场景更多依赖上游解析配置) |
因此,可以把 mihomo 理解为“面向通用流量的策略路由引擎”,而 Nginx 是“面向 HTTP 服务治理的请求路由引擎”。
一个简化的配置骨架
mode: rule
proxies:
- { name: "node-hk-01", type: vless, server: "example.com", port: 443, uuid: "<uuid>", tls: true }
- { name: "node-sg-01", type: hysteria2, server: "example.net", port: 443, password: "<password>" }
proxy-groups:
- { name: "Auto", type: url-test, proxies: ["node-hk-01", "node-sg-01"], url: "http://www.gstatic.com/generate_204", interval: 300 }
- { name: "Manual", type: select, proxies: ["Auto", "node-hk-01", "node-sg-01", "DIRECT"] }
rules:
- DOMAIN-SUFFIX,example.cn,DIRECT
- DOMAIN-SUFFIX,google.com,Manual
- GEOIP,CN,DIRECT
- MATCH,Manual
这个骨架对应的设计意图是:
proxies只描述节点能力。proxy-groups提供自动与手工两层策略。rules把业务流量映射到策略,而不是绑死到某个节点。
面向长期维护的配置建议
- 规则层始终保留兜底
MATCH,<group>,避免漏流量。 - 业务规则、地域规则、兜底规则按顺序分段,保证 first-match 可预测。
- 对高频变更的数据(节点、规则集)优先 provider 化,主配置只保留编排。
- 对关键组(如
url-test/fallback)统一健康检查参数,减少策略行为漂移。 - 排障时用
mode: global/direct快速隔离“规则问题”与“节点问题”。
总结
proxies 是“能力抽象”,proxy-groups 是“策略抽象”,rules 是“决策抽象”。三者解耦,是 mihomo 配置能够持续扩展、方便运维并且易于排障的核心设计。