Clash 自定义规则写法详解:匹配类型、语法格式与优先级顺序

覆盖 DOMAIN、DOMAIN-SUFFIX、IP-CIDR、PROCESS-NAME 等常用规则类型的语法与适用场景,重点讲清自上而下的匹配优先级、no-resolve 参数与规则排序的实战原则。

Clash 的分流能力最终都落在配置文件的 rules 字段上。一条规则决定一类流量走哪个代理组,写错顺序或用错匹配类型,轻则某个网站分流不生效,重则整段代理组失效、DNS 解析异常。这篇文章按 mihomo 内核(Clash Meta)的实现,把常用规则类型逐一拆开讲清楚语法与适用场景,再讲清楚规则是怎么"从上到下"生效的,最后给出一套可以直接照搬的排序思路。

规则系统的基本结构与生效顺序

Clash 配置文件里的 rules 是一个数组,每一行是一条规则,格式统一为:

规则类型,匹配内容,策略组[,附加参数]

比如:

rules:
  - DOMAIN-SUFFIX,github.com,🚀 节点选择
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - GEOIP,CN,DIRECT
  - MATCH,🚀 节点选择

内核处理一条网络请求时,会按数组顺序从上往下逐条比对,一旦某条规则匹配成功,立即采用它指定的策略组,后面的规则全部跳过,不会继续往下匹配。这个"命中即停止"的机制是整套规则系统里最容易被忽略、也最容易出问题的一点——很多人以为规则是"谁更精确谁生效",实际上完全取决于写在前面还是后面。

正因为如此,规则文件末尾几乎总会看到一条 MATCH,策略组 兜底,它代表"以上所有规则都没有命中时的默认走向",相当于分流表的最后一行,必须放在数组最末尾,放在前面会导致后面所有规则永远失效。

常用匹配类型逐一拆解

mihomo 支持的规则类型很多,但日常配置里高频出现的其实就下面几类,按匹配对象可以分成域名类、IP 类、地理位置类和进程类。

域名类:DOMAIN / DOMAIN-SUFFIX / DOMAIN-KEYWORD

  • DOMAIN,www.example.com,策略组 —— 精确匹配单个完整域名,子域名不会被命中,适合只想单独处理某一个具体域名的场景。
  • DOMAIN-SUFFIX,example.com,策略组 —— 匹配该域名及其所有子域名(www.example.comapi.example.com 都算命中),日常配置里最常用的一种,写一条规则能覆盖一整个域名体系。
  • DOMAIN-KEYWORD,example,策略组 —— 只要域名中包含这个关键字就命中,匹配范围最宽,容易误伤无关域名,建议只在关键字足够特殊、不会与其他服务重名时使用。

IP 与网段类:IP-CIDR / IP-CIDR6

IP-CIDR,192.168.1.0/24,DIRECT,no-resolve 这类规则按 CIDR 网段匹配目标 IP,常用于把局域网段、内网服务器、CDN 固定 IP 段直接放行或强制走某条线路。IPv6 地址对应 IP-CIDR6,写法完全一致。这类规则通常需要放在规则表靠前的位置,因为很多局域网访问一旦被域名规则或 GEOIP 规则先行拦截,反而会绕一圈走代理。

地理位置类:GEOIP

GEOIP,CN,DIRECT 依赖 GeoIP 数据库判断目标 IP 所属国家或地区,常见写法是把 GEOIP,CN 对应到直连策略,让国内 IP 不走代理。这类规则天然放在整个规则表偏后的位置,因为它的匹配范围极宽,一旦放在前面会把大量本应细分处理的流量提前"收编"掉。

进程类:PROCESS-NAME / PROCESS-PATH

PROCESS-NAME,com.apple.WebKit.Networking,DIRECT 按发起请求的进程名匹配,常用于给特定客户端单独指定策略,比如让某个下载工具始终直连,或者让某个应用始终走特定节点。桌面平台上进程类规则的粒度最细,但要注意进程名在不同系统、不同版本之间可能有差异,不生效时优先检查名称是否写对。

逻辑组合与兜底:AND / OR / NOT / MATCH

mihomo 还支持逻辑规则,把多个子条件组合成一条,例如:

- AND,((DOMAIN-SUFFIX,example.com),(NETWORK,tcp)),策略组

这类写法适合需要同时满足多个条件才生效的精细场景,日常配置里出现频率不高,但了解语法结构对读懂社区分享的规则集很有帮助。最后,MATCH,策略组 是唯一不需要匹配内容的规则类型,代表兜底策略,规则表里只应该出现一次,且必须在最后一行。

no-resolve 参数与 DNS 解析时机

IP-CIDR 与 IP-CIDR6 规则可以在末尾加上 no-resolve 参数,这是实战中最容易被忽略、又最容易导致规则"看起来没生效"的一个细节。

默认情况下,一条基于域名的规则(比如 DOMAIN-SUFFIX)命中前不需要提前解析 IP,直接按域名字符串比对;而 IP-CIDR 类规则本质上是拿"目标 IP"去和网段比对,如果请求本身是一个域名,内核需要先把域名解析成 IP,再拿这个 IP 去匹配 IP-CIDR 规则。加上 no-resolve 之后,内核会跳过这一步解析,只对那些请求本身已经是 IP(而不是域名)的连接生效,不会主动为了匹配规则去发起额外的 DNS 查询。

如果一条 IP-CIDR 规则的目标网段本来就该拦截域名请求提前触发的解析(比如内网服务只用域名访问),不加 no-resolve 会导致每次匹配都先发出一次额外的 DNS 查询,增加延迟且可能把解析请求发到了不该经过的 DNS 服务器。反过来,如果只是想给"纯 IP 直连"的流量做规则,加上 no-resolve 能减少不必要的解析开销。

实际写规则时的判断标准很简单:如果这条 IP-CIDR 规则针对的是明确会以 IP 形式出现的流量(比如内网设备、某些直接暴露 IP 的服务),建议加 no-resolve;如果目标本身是通过域名访问、需要依赖解析结果才能判断走向的场景,交给前面的域名类规则处理会更直接,没必要绕到 IP-CIDR 上。

规则排序的实战原则与常见错误

理解了"从上到下命中即停止"的机制后,规则排序其实有一套相对固定的思路,按匹配范围从窄到宽排列:

  1. 先写局域网与内网直连规则。私有 IP 段、内网域名放在最前面,避免被后面更宽泛的规则提前拦截,导致内网访问也走了代理。
  2. 再写需要特殊处理的具体域名或应用。比如要求走特定节点的流媒体域名、需要直连的国内常用服务域名,用 DOMAIN-SUFFIX 精确覆盖。
  3. 接着放规则集合(rule-providers)。社区维护的分类规则集,比如广告过滤、常见服务分类,按需要引用的顺序排列。
  4. 再放地理位置类规则。典型是 GEOIP,CN,DIRECT,把没被前面规则命中的国内 IP 直接放行。
  5. 最后一条固定是 MATCH 兜底。所有没命中的流量统一走这里,通常指向节点选择或代理组。

常见的排序错误集中在两类:一类是把 GEOIP,CN,DIRECT 写得太靠前,导致本应细分走代理的服务因为解析出的 IP 恰好在国内网段而被提前直连;另一类是把 MATCH 兜底规则误放在中间位置,后面辛苦写的所有规则实际上永远不会被执行到,调试时容易误以为是某条具体规则语法错了,其实是排序问题。排查这类问题时,建议先看规则数组顺序,再看具体语法,顺序错了,语法再精确也不会生效。

用规则集合组织大规模规则

当自定义规则条数增长到几十上百条,直接堆在 rules 数组里会变得难以维护。mihomo 支持 rule-providers 字段,把规则拆分成独立的远程或本地文件,再在 rules 里通过 RULE-SET,规则集名称,策略组 引用:

rule-providers:
  my-direct:
    type: http
    behavior: domain
    url: "https://example.com/rules/direct.yaml"
    path: ./rule-providers/direct.yaml
    interval: 86400

rules:
  - RULE-SET,my-direct,DIRECT
  - GEOIP,CN,DIRECT
  - MATCH,🚀 节点选择

behavior 字段决定这份规则集里的条目按域名、IP 网段还是分类规则解析,需要与规则文件实际内容对应;interval 决定多久自动拉取一次更新。这种方式把"分类逻辑"和"具体规则内容"解耦,规则集本身的更新不需要改动主配置文件里的排序,维护成本明显低于把所有规则手写在同一份配置里。

写规则前后建议做的两项检查

写完规则后,建议做两件事再上线使用:第一,检查规则数组里是否只有一条 MATCH 且位于末尾,这是最容易漏检的一处;第二,针对新增的 IP-CIDR 规则,确认 no-resolve 是否按预期添加或省略,尤其是涉及内网访问的规则,加错或漏加都会带来看似"随机"的连接异常。日志里出现的分流结果如果和预期不符,先回到规则数组按顺序读一遍,通常比逐条检查语法更快定位问题。

下载 Clash iOS 客户端

规则语法与优先级在各平台通用,先在设备上装好客户端,再逐条验证分流是否符合预期。

下载客户端