规则结构与生效前提

Mihomo 的 rules 是有顺序的规则列表。常见格式是 规则类型,匹配内容,目标策略;最后的兜底规则写成 MATCH,目标策略。目标可以是内置的 DIRECT、REJECT,也可以是配置中已经定义的代理或策略组名称。

规则决定连接交给谁处理,不负责自动接管系统全部流量。浏览器使用系统代理、应用手动指定代理,或者客户端通过 TUN 接管连接,都会影响内核能否看到请求。若连接列表根本没有该应用的流量,应先检查接入方式,再修改规则。

先确认三个条件

  • 当前模式为 rule。Global 模式不按这份普通规则列表逐条分流;Direct 模式则走直连。
  • 编辑的是正在运行的配置,且已完成保存与重载。客户端编辑器中的文本不一定等于内核实际加载的内容。
  • 所有目标策略确实存在。例如规则使用 PROXY,配置中就必须有同名代理或策略组,大小写与空格都应一致。
mode: rule

rules:
  - DOMAIN,example.com,DIRECT
  - DOMAIN-SUFFIX,example.org,DIRECT
  - MATCH,PROXY

以上是合并到现有配置的片段,不是包含节点、DNS 与监听端口的完整配置。示例假定现有策略组名为 PROXY;如果实际组名是“节点选择”,应把对应目标改成该组名。example.com 与 example.org 是文档示例域名,实际使用时按要分流的服务修改。

DOMAIN 类规则:精确、后缀与关键词

域名规则适合网站与按域名提供的 API 服务。选择规则类型时,应先确定匹配范围,而不是把所有域名都写成关键词。关键词范围过大,容易把名称相近但无关的服务一并分流。

类型 示例 匹配范围
DOMAIN DOMAIN,api.example.com,DIRECT 仅精确域名 api.example.com
DOMAIN-SUFFIX DOMAIN-SUFFIX,example.com,DIRECT example.com 及其子域名
DOMAIN-KEYWORD DOMAIN-KEYWORD,example,DIRECT 域名中包含 example 的目标

规则里不写协议与页面路径

DOMAIN 的匹配内容应为域名,不是完整 URL。把 https://api.example.com/v1 放进 DOMAIN 规则,不能按网页路径分流。普通域名规则也不区分同一域名下的两个页面。

rules:
  - DOMAIN,api.example.com,PROXY
  - DOMAIN-SUFFIX,example.com,DIRECT
  - MATCH,PROXY

这组规则先把 api.example.com 交给 PROXY,其余 example.com 子域名再直连。它依赖书写顺序,而不是 DOMAIN 自动获得更高优先级。若交换前两行,后缀规则会提前命中,精确规则便没有执行机会。

GEOSITE 与规则集:分类不等于固定清单

GEOSITE 使用域名分类数据。例如 GEOSITE,cn,DIRECT 表示匹配当前 geosite 数据中名为 cn 的分类。它不是按网站服务器所在地判断,也不等于识别所有中文网页。实际命中范围取决于所用数据源及其更新状态。

rules:
  - DOMAIN,api.example.com,PROXY
  - GEOSITE,cn,DIRECT
  - GEOIP,CN,DIRECT,no-resolve
  - MATCH,PROXY
  • GEOSITE 面向域名分类,GEOIP 面向目标 IP 所属分类,两者不能互换。
  • 引用前需保证相应数据可用。缺少数据文件、下载失败或分类名不存在,都可能导致加载报错。
  • 自定义例外放在分类规则之前。例如某个域名需要走代理,就不要把它排在已覆盖该域名的直连分类之后。

RULE-SET 需要先定义 provider

RULE-SET 引用 rule-providers 中的名称。下面使用本地文件,避免把远程下载故障与匹配故障混在一起。文件路径相对于内核的工作目录,客户端可能对允许访问的位置另有限制。

rule-providers:
  local-direct:
    type: file
    behavior: domain
    format: yaml
    path: ./rules/local-direct.yaml

rules:
  - RULE-SET,local-direct,DIRECT
  - MATCH,PROXY

对应的 local-direct.yaml 内容为:

payload:
  - 'example.com'
  - '+.example.org'

behavior: domain 的 payload 填域名匹配项;+.example.org 覆盖该域名及其子域名。若采用 behavior: classical,payload 则应填写 DOMAIN-SUFFIX,example.org 等规则表达式,出口通常由外层 RULE-SET 指定。不要把两种内容格式混用,也不要仅凭文件扩展名判断规则集类型。

IP-CIDR 与 no-resolve:目标地址匹配

IP-CIDR 匹配 IPv4 地址段,IP-CIDR6 匹配 IPv6 地址段。斜杠后是前缀长度:/32 表示单个 IPv4 地址,/24 表示包含 256 个地址的网段。这里判断的是目标地址,不是访问设备所在的源地址。

rules:
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,172.16.0.0/12,DIRECT,no-resolve
  - IP-CIDR6,fc00::/7,DIRECT,no-resolve
  - MATCH,PROXY

no-resolve 不会关闭 DNS

no-resolve 表示不为当前 IP 类规则主动触发域名解析。如果连接已经带有可用的目标 IP,仍然可以匹配;若连接只有域名且尚无可用 IP,就可能跳过该条 IP 判断,继续检查后面的规则。它不是全局 DNS 开关,也不保证域名在其他阶段完全不被解析。

因此,给 IP 规则添加 no-resolve 后,不能假设某个域名一定会按最终解析出的地址分流。需要明确直连的内网域名,通常还应配置对应的域名规则,并检查内核 DNS 是否能通过正确的内网解析器得到地址。

PROCESS-NAME:进程识别与权限边界

PROCESS-NAME 按进程名称匹配,适合需要整款应用走同一出口的场景。它依赖内核从操作系统获取进程信息,不是从域名推断应用身份。可用性受操作系统、客户端实现、运行权限与流量接入方式影响。

find-process-mode: strict

rules:
  - PROCESS-NAME,curl,DIRECT
  - PROCESS-NAME,curl.exe,DIRECT
  - DOMAIN-SUFFIX,example.com,PROXY
  - MATCH,PROXY

strict 是按需查找进程的模式。排查时可以临时改为 always,观察是否能取得进程信息;确认后再按实际需求调整。进程名应以连接详情或系统实际可执行文件名称为准,不能直接照抄桌面快捷方式名称。

  • Windows 中常见名称带 .exe;其他桌面系统的可执行文件名可能不同。
  • 浏览器、启动器和下载工具可能使用子进程。主窗口名称与真正建立连接的进程名称未必一致。
  • 如果请求经由另一个本地代理程序转发,内核可能只能识别转发程序,无法还原最初发起请求的应用。
  • TUN 可以接入更多应用流量,但不代表所有平台都会提供完整进程信息;进程字段为空时,应先核查权限与平台能力。

进程规则放在域名规则前,意味着该进程的连接会先按进程策略处理。如果希望浏览器中的个别网站直连,而其他网站走代理,应把域名例外放在浏览器进程规则之前。

匹配顺序:首条命中与 MATCH 兜底

对本文涉及的普通规则列表,可以按“从上到下检查,首条命中后选定目标”理解。内核不会为了寻找更长的域名后缀而跳过已经命中的规则,也不会自动把进程规则排到域名规则前面。

常见错误:宽规则覆盖窄规则

rules:
  - DOMAIN-SUFFIX,example.com,DIRECT
  - DOMAIN,api.example.com,PROXY
  - MATCH,PROXY

这里访问 api.example.com 会先命中第一行。修复方法是把精确例外移到后缀规则之前,而不是重复追加同一条规则。类似地,位于前面的 GEOSITE、RULE-SET 或进程规则,也可能提前覆盖后面的自定义条目。

推荐的组织顺序

  1. 少量明确的例外:指定域名、指定进程或特殊地址。
  2. 局域网与内网服务:按实际环境安排域名和地址段。
  3. 业务规则集与地区分类:范围较大,先检查是否相互覆盖。
  4. MATCH:最后兜底,处理未被前面规则匹配的连接。

这个顺序是维护建议,不是内核强制要求。若局域网直连必须优先于某个进程代理规则,应把局域网规则放得更靠前。MATCH 没有匹配内容字段,写成 MATCH,PROXY 即可;放在列表中间,会让后续普通规则失去命中机会。

命中策略组还不等于确定最终节点。例如规则交给 PROXY,但该组当前选中 DIRECT,实际连接仍会直连。排查时要分开看“命中了哪条规则”和“策略组最后选了哪个出口”。

规则不生效:按连接证据逐项检查

不要一次修改 DNS、TUN 和整份规则。先选一个可重复访问的目标,记录目标域名、请求时间、命中规则、策略链和日志错误,再只改一个变量。不同客户端的菜单名称不统一,应寻找对应的连接详情、运行日志与当前配置视图。

  1. 确认连接进入内核。发起新请求后,在连接列表搜索目标域名或进程。没有记录时,检查系统代理、应用代理地址或 TUN 接管范围。
  2. 确认监听端口。若配置为 mixed-port: 7890,测试工具就应连接 127.0.0.1:7890,不能沿用其他客户端的端口。
  3. 确认当前模式与加载结果。检查是否为 Rule,并查看重载时是否出现 YAML、未知策略或规则集加载错误。
  4. 确认实际匹配内容。核对访问是否跳转到另一域名,或由多个静态资源、API 域名共同组成。只分流页面主域名,不代表全部资源都走同一路径。
  5. 从命中规则向前检查。寻找更靠前的 DOMAIN-SUFFIX、GEOSITE、RULE-SET、进程规则或 MATCH,确认是否提前截获目标。
  6. 确认出口与新连接。检查策略组当前选择,并关闭旧连接或重启测试应用。配置重载后,已有长连接不应被当作新规则的测试样本。

用 curl 固定测试入口

以下命令适用于已经启用 mixed-port: 7890 的本机配置。--noproxy "" 清空本次请求的代理绕过列表,减少环境变量对测试的干扰;-I 发起 HEAD 请求,主要用于观察连接建立及规则命中。Windows PowerShell 可使用 curl.exe 明确调用可执行文件。

curl --noproxy "" -I --proxy http://127.0.0.1:7890 https://example.com
curl --noproxy "" -I --proxy socks5h://127.0.0.1:7890 https://example.com

socks5h 会把目标域名交给代理端处理,适合减少本地提前解析带来的差异。这两条命令用于核对显式代理路径,不代表已经验证 TUN 路径。测试 TUN 时,需要另行确认应用未使用显式代理,并结合客户端连接记录判断流量是否真正进入虚拟网卡。

现象 优先检查 处理方向
保存后配置无法重载 缩进、策略名称、分类数据、规则集格式 按日志行号修复,确认使用空格缩进
始终命中 MATCH 域名是否一致、进程信息是否可用 查看连接实际字段,不只看地址栏
命中 PROXY 仍然直连 策略组是否选中 DIRECT 或嵌套直连组 展开完整策略链检查最终出口
更新订阅后自定义规则消失 是否直接编辑订阅生成文件 使用客户端支持的持久化覆写机制

订阅更新与规则维护

订阅可能提供完整配置,也可能只提供节点。直接修改完整订阅生成的文件,下一次更新时可能被替换。若客户端提供覆写、合并或脚本处理功能,应先确认它如何处理 rules:是整体替换、向前插入,还是追加到末尾。

追加到末尾尤其容易造成“规则存在但没有生效”。如果原始订阅已经以 MATCH 结束,新增条目必须在最终生效配置中位于 MATCH 之前。不要只检查覆写编辑框;应核对合并后的规则顺序,并用一条新连接验证。

保留可回退的修改记录

  • 一次只增加一组用途明确的规则,记录目标域名、预期出口与添加原因。
  • 本地规则集与主配置一起备份,避免只恢复 YAML 后丢失外部文件。
  • 更新客户端或内核后,重新检查进程识别、规则集加载和关键例外,不依赖旧连接结果。
  • 分享日志前隐藏订阅地址、节点认证信息和控制接口密钥。排查优先提供规则片段与命中信息。

规则维护的核心是让范围与顺序可解释:精确例外放在会覆盖它的宽规则前,兜底放最后,连接详情用于确认实际命中。先验证流量入口,再验证匹配字段,最后检查策略链,通常比反复切换模式更容易定位问题。