排查顺序

模块装上了但没效果,按这个顺序查:

  1. 模块在列表里开着吗?客户端不在「直连」或「全局」模式吗?这两个模式下所有模块规则整体失效。
  2. 规则命中了吗?—— 换成 REJECT 试一次。如果目标彻底连不上,说明规则命中了,问题在出口;如果照常能连,说明规则没命中。
  3. 匹配值有没有写成大写?域名类的值必须自己写小写,大写永远不命中。
  4. 有没有把注释写在规则行尾?行尾注释会被并进出口名。
  5. 出口名在 [Proxy Group] 里定义过吗?未定义且不是客户端已有出口名时,规则会使用「默认」出口,且不会显示错误。
  6. 用到 GEOIP / GEOSITE 的,名字拼对了吗?模块详情页里那个规则集下载到多少条?0 条 = 永远不命中。
  7. 用到改写或脚本的:解密开关开了吗?根证书装了并且完全信任了吗?目标域名写进 [MITM] hostname 了吗?
  8. 还是不行,看日志。

没有错误提示但未生效

这是最常见的一类。原因几乎总在下面这张表里。

现象 原因
匹配值写了大写 只有被匹配的域名被转小写,规则里的值原样使用。DOMAIN-SUFFIX,Google.COM 永不命中
规则行尾写了 # 注释 没有行尾注释,DIRECT # 注释 整个被当成出口名,落到「默认」
规则已配置,流量仍使用原出口 出口名未定义,因此使用了「默认」出口
规则针对私网 IP / BT / ping 客户端有前置规则把它们判给直连,排在所有模块规则之前
客户端在「直连」或「全局」模式 这两个模式下模块规则整体不参与
GEOSITE,xxx 从不命中 名字在规则集目录里不存在,下载 404,规则空转
GEOSITE / GEOIP 刚导入时不命中 规则集还没下载完,等一会或在模块详情页手动重拉
前面存在更宽泛的规则 规则从上到下匹配,第一条命中后停止。GEOSITE,cn,DIRECT 写在特定境外服务规则之前时,后者可能没有机会匹配
改写/脚本一点动静没有 域名没写进 [MITM] hostname;或者根证书没「完全信任」;或者你在 Android 上
[MITM] hostname 只剩排除项 一条包含规则都没有时整个解密层不启用
YouTube / Google 系的改写不生效 走了 HTTP/3,没经过解密层。加一条 UDP 阻断规则
脚本启用后没有效果 脚本可能抛出异常。发生异常时请求保持原样继续处理,客户端不显示脚本错误
[Body Rewrite] / [Map Local] 里的双引号消失 这些配置段解析时会移除双引号,且不支持 \"。正则中使用 \x22,正文使用 data-type=base64
[URL Rewrite] 整行没生效 行尾动作拼错了,比如 reject-img-drop、reject-200-no-drop 这些不存在的组合
DST-PORT,80-443 不生效 不支持端口区间,只能写单个端口
URL-REGEX / USER-AGENT 规则不生效 这些类型不受支持,配置会被忽略。按路径拦截应使用 [URL Rewrite]
新建的分组未显示 分组名与已有出口重名,新分组被忽略
分组只剩一个成员 手写的成员名都没定义过,合并成同一个「默认」出口了

内核无法启动或节点列表为空

配置被拒绝了,三个原因:

  1. 分组正则用了 RE2 不支持的语法 —— policy-regex-filter / exclude-regex 里写了环视 (?= (?! (?<= (?<! 或反向引用 \1。这是最常见的一个。
  2. 分组是空的 —— 既没写成员也没写正则筛选(我的组 = select),或者写的成员全被丢掉(广告 = select, REJECT)。
  3. 规则里的值非法 —— IP-CIDR 的值不是合法 IP 或网段,DOMAIN-REGEX 的正则编译不过。

解决:关掉刚装的模块,如果恢复了就是它;逐条对照上面三点改。

分组重名不会阻止内核启动。 重名时新分组会被忽略,内核仍可正常运行;此时表现为新分组未显示,而不是节点列表为空。重复安装同一模块时也是如此。

写法陷阱

注释只能独占一行

# 对
DOMAIN-SUFFIX,a.com,DIRECT

# 错:出口变成了 "DIRECT # 走直连",落到「默认」
DOMAIN-SUFFIX,a.com,DIRECT # 走直连

匹配值要写小写

# 错,永不命中
DOMAIN-SUFFIX,Google.COM,默认

# 对
DOMAIN-SUFFIX,google.com,默认

GEOIP / GEOSITE 的名字例外,大小写都行。

逗号

[Proxy Group] 的定义按逗号切分。正则里带 {2,3} 这类量词时整个值要用双引号包起来:

测试 = url-test, policy-regex-filter="(?i)节点[0-9]{2,3}", interval=300

[Script] 的 KV 列表也按逗号切,但不含 = 的片段会自动并回上一段,所以 pattern 里的量词、argument 里的 JSON 一般不会被切断。但 argument 的值里出现 = 就会被当成新的 key,那一串从此断掉。

双引号会在解析时被移除

[URL Rewrite] / [Header Rewrite] / [Body Rewrite] / [Map Local] 四个配置段按空白分隔字段,解析时会移除所有双引号,且不支持 \" 转义:

  • 正则或替换串里要一个字面双引号,写 \x22。
  • 要输出一段 JSON,用 [Map Local] 的 data-type=base64,或者用 [Body Rewrite] 的 jq 变体。
  • 值里要有空格,把整段用双引号包住(引号本身会被剥掉,起的是「不切分」的作用)。

正则用的是 RE2

分组筛选、规则里的 DOMAIN-REGEX、改写和脚本的 pattern,全部是 RE2:

  • 没有环视:(?=) (?!) (?<=) (?<!)
  • 没有反向引用:\1 \2
  • (?i) 可以用,写在开头

从其他客户端移植正则时需要检查这两项。JavaScript 支持这些语法,但此处不支持;用于分组筛选时会导致内核无法启动。

*.example.com 不含 example.com

[MITM] hostname 里的 *.example.com 只匹配子域。主域要单独写一条:

hostname = example.com, *.example.com

DOMAIN-SUFFIX,example.com 则是两个都匹配,不用重复写。

[MITM] 里的排除优先

只要命中任何一条 - 排除,就一定不解密,不管别的规则怎么写。全是排除项时整个解密层不启用。

FINAL 会替换全局默认规则

FINAL 指定其他规则均未命中时使用的出口,并替换客户端原有的默认规则。仅修改少量域名出口时不要配置 FINAL。配置多条时最后一条生效;FINAL,REJECT 会被忽略。

模块不能定义节点

[Proxy] 段会被忽略。节点由客户端管理,模块只能通过 [Proxy Group] 的正则筛选引用节点。[General] 仅支持 dns-server,其他全局设置不受模块控制。

DNS 配置没生效

  • 地址写成域名:server:dns.corp.local 整条被丢掉,只收 IP(可带端口和 tls:// https:// 前缀)或 system。
  • 域名模式写成裸通配:单独一个 * 或 +. 不接受,得写到具体域名(+.corp.com)。
  • 目标是修改节点或入口域名的解析:模块 DNS 配置只作用于用户访问的目标域名;节点和入口域名固定使用客户端内置的解析路径。
  • 解析出内网地址但连不上:再补一条 DOMAIN-SUFFIX,内网域名,DIRECT,否则地址可能被路由进代理。
  • 只写了 [Rule] 想把内置判直连的域名改走节点:改不动。那条规则确实生效了,但 DNS 可能已经获得中国大陆的真实 IP,随后流量仍会经代理连接该地址。应同时配置 [Host] 域名 = server:fakeip,分配虚拟 IP 并由 [Rule] 决定出口。

一行一个值

# 错:b.com 被解析为出口名,规则将使用「默认」出口且不显示错误
DOMAIN-SUFFIX,a.com,b.com,默认

# 对
DOMAIN-SUFFIX,a.com,默认
DOMAIN-SUFFIX,b.com,默认

关于解密

  • Android 端不支持,[MITM] 及其后面几段永远不生效。
  • 做了证书钉扎的 App 连不上,没有绕过办法。这不是配置写错了。
  • 不要写 hostname = *。全量解密会让设备明显变慢,还会让一批 App 直接连不上。
  • 证书装完之后,iOS 上还要去「设置 → 通用 → 关于本机 → 证书信任设置」里勾上。少这一步全部改写都不生效,而且没有任何提示。

导入时的提示

  • 规则集名字核对失败:GEOIP / GEOSITE 的名字在目录里不存在,改掉。
  • 提示「无法核对」:一般是网络不通,规则集本身可能是对的,连上网再看。

除此之外没有其他导入提示。不支持的规则类型、无效改写行和被忽略的重名分组不会显示错误。导入成功仅表示文件可读取,不表示每一行配置都已生效。