进阶技巧 预计阅读 13 分钟

自定义路由规则写法:domain、ip、geosite 语法与匹配优先级说明

路由规则决定哪些流量走代理、哪些直连。本文拆解 domain 前缀语法、ip/CIDR 写法与 geosite 数据集用法,说明规则自上而下的匹配顺序,并给出几组可直接套用的常用规则组合。

先看清路由规则处理的是什么

V2Ray 与 Xray 的路由模块位于入站和出站之间。应用流量进入内核后,路由模块读取目标域名、目标 IP、端口、网络类型、入站标签等信息,再把这条连接交给某个出站。常见出站标签包括代理连接使用的 proxy、本地直连使用的 direct,以及拒绝连接使用的 block。这些名称不是固定关键字,而是配置中 outbounds 项目的 tag;规则里的 outboundTag 必须与实际标签完全一致。

VMess、VLESS 等协议负责客户端与远端之间如何传输数据,路由规则则负责选择哪一条出站。两者处在不同层面。更换 VMess 为 VLESS,不会自动改变分流结果;导入新订阅,也不代表原有自定义规则一定继续适用。使用 v2rayN、v2rayNG 或 v2flyNG 时,应分别检查当前配置、路由模式和内核类型,确认规则最终被写入正在运行的配置。

一条典型字段规则由 type、匹配条件和目标出站组成。当前常用的类型是 field。同一条规则可以包含多个条件类别,例如同时限定域名和端口;不同类别通常需要同时满足。同一类别中的多个值则表示候选集合,只要命中其中一个即可进入该规则。

{
  "type": "field",
  "domain": [
    "domain:example.com",
    "full:api.example.net"
  ],
  "port": "443",
  "network": "tcp",
  "outboundTag": "proxy"
}

这条示例只处理 TCP 443 端口,并且目标域名符合两个域名条目之一。若访问的是同一域名的 80 端口,它不会命中。实际配置时不要为了“更精确”随意叠加条件;每增加一种条件,都可能把原本需要处理的连接排除在外。

domain 的四种常用匹配写法

domain 数组不只接收完整域名。前缀决定内核如何解释每个条目。最常用的写法是 full:domain:regexp: 和不带前缀的纯字符串。选错前缀常会造成匹配范围过宽,或者只命中主域名却漏掉子域名。

写法 匹配范围 适合场景
full:www.example.com 仅匹配完整目标域名 单独处理一个明确主机名
domain:example.com 匹配根域名及其子域名 处理一个站点及其常见子域
regexp:^api\d+\.example\.com$ 按正则表达式匹配 域名有稳定编号或固定格式
example 按域名关键字匹配 需要覆盖包含特定片段的域名

full::只接住一个准确域名

full:api.example.com 适合接口主机、更新服务器等边界清楚的目标。它不会把 www.example.comcdn.api.example.com 一并算进去。若只想调整某个子域名,不希望影响同一主域下的其他服务,应优先使用 full:

domain::覆盖根域名和下级子域

domain:example.com 会处理 example.com,也会处理 www.example.comstatic.example.com 等下级域名,但不会把名称结尾相似、边界不同的域名算作同一站点。按站点整体分流时,这通常比关键字写法更稳妥。

纯字符串和正则:范围更宽,使用要克制

不带前缀的值按关键字思路匹配。条目 example 可能覆盖多个名称中带有该片段的域名,适合目标域名变化较多且命名规律明确的情况,但也更容易误伤无关站点。正则表达式控制力更强,同时会增加维护和排错成本。能用 full:domain: 表达时,没有必要先写复杂正则。

{
  "type": "field",
  "domain": [
    "full:status.example.com",
    "domain:media.example.net",
    "regexp:^edge-[0-9]+\\.example\\.org$"
  ],
  "outboundTag": "proxy"
}

JSON 字符串中的反斜杠需要转义,因此正则里的 \. 在 JSON 文件中要写成 \\.。这是很多“正则单独测试正常,放进配置却无法启动”问题的来源。保存后若内核立即退出,应先查看运行日志中的 JSON 解析错误和规则解析错误。

ip、CIDR 与 geoip 的写法

ip 数组用于匹配目标 IP,可以放单个地址、CIDR 网段,也可以引用 geoip 数据集。单个地址适合固定服务器,CIDR 适合连续网段。IPv4 的 192.0.2.0/24 表示从该网络前缀覆盖的一组地址;IPv6 也采用前缀长度写法,例如 2001:db8::/32

{
  "type": "field",
  "ip": [
    "192.0.2.25",
    "198.51.100.0/24",
    "2001:db8::/32"
  ],
  "outboundTag": "direct"
}

CIDR 的重点是网络前缀,而不是起止地址的文字缩写。前缀长度越大,范围越小。IPv4 中 /32 只指向一个地址,/24 通常覆盖同一前缀下的 256 个地址。不要把服务商当前解析出的某个地址直接扩成过大的网段,否则同一网络中的无关服务也会被改道。

geoip:private 常用于匹配私有网络和本地用途地址,适合作为直连规则的一部分。这样访问局域网网关、内部面板或本地设备时,不会被送往远端代理。若启用了 TUN 等更广范围的流量接管方式,私有地址直连规则尤其需要放在通用代理规则之前。

{
  "type": "field",
  "ip": [
    "geoip:private"
  ],
  "outboundTag": "direct"
}

geoip:cn 这类条目依赖当前内核加载的 IP 数据文件。数据集表达的是一批网络地址,不等同于域名集合,也不保证某个站点的所有服务器始终属于同一地区。大型站点经常使用内容分发网络,同一个域名在不同网络、不同时间可能解析到不同地址,因此仅靠 IP 地理集合进行站点级分流并不总是稳定。

geosite 是域名集合,不是协议名称

geosite: 写在 domain 数组中,用于引用预先整理的域名集合。例如 geosite:cn 常用来表示一组对应类别的域名,geosite:category-ads-all 常用来表示广告相关域名集合。具体可用名称取决于当前数据文件;名称不存在、文件未加载或数据版本不匹配时,规则可能无法正常生效。

{
  "type": "field",
  "domain": [
    "geosite:cn"
  ],
  "outboundTag": "direct"
}

geosite 的优点是不用手工维护大量域名。它适合构建基础分流层,但不应被理解成实时在线查询。数据文件更新后,集合内容才会变化。遇到新域名暂未收录时,可以在 geosite 规则之前增加一条明确的 full:domain: 规则,先修正当前路径,再考虑更新数据。

若要使用广告类别进行阻断,必须先在出站中配置对应的拒绝出站,并让规则引用正确标签。仅写 outboundTag: "block" 而完整配置中没有 block 标签,并不能形成有效链路。

{
  "type": "field",
  "domain": [
    "geosite:category-ads-all"
  ],
  "outboundTag": "block"
}

按类别分流时还要留意例外需求。假设一个域名被集合规则判定为直连,但当前网络中必须走代理,那么应把该域名的明确代理规则放到集合规则前面。反过来,如果某个域名被宽泛的代理集合覆盖,却需要固定直连,也要先写更具体的直连规则。

匹配优先级:规则自上而下,命中后停止

路由规则按 rules 数组中的顺序依次检查。第一条满足条件的规则决定出站,后面的规则不再参与。这意味着“更具体的规则”不会自动获得更高优先级,真正的优先级就是排列位置。即使第二条使用 full: 精确匹配,只要第一条宽泛规则已经命中,第二条也没有机会执行。

下面的顺序会让 full:special.example.com 的直连规则失效,因为前面的 domain:example.com 已经覆盖它:

[
  {
    "type": "field",
    "domain": [
      "domain:example.com"
    ],
    "outboundTag": "proxy"
  },
  {
    "type": "field",
    "domain": [
      "full:special.example.com"
    ],
    "outboundTag": "direct"
  }
]

正确做法是把例外放在前面,把覆盖面更广的规则放在后面:

[
  {
    "type": "field",
    "domain": [
      "full:special.example.com"
    ],
    "outboundTag": "direct"
  },
  {
    "type": "field",
    "domain": [
      "domain:example.com"
    ],
    "outboundTag": "proxy"
  }
]

整理顺序时可以采用“本地保护、明确例外、分类集合、区域规则、最终兜底”的思路:

  1. 先处理私有网络、局域网和必须保留的本地连接。
  2. 再放单个域名、单个 IP 等明确例外。
  3. 随后放 geosite、geoip 和较大的 CIDR 集合。
  4. 最后使用覆盖 TCP、UDP 的通用规则决定剩余流量。

通用兜底规则一定要放在末尾。若把 network: "tcp,udp" 的代理规则放在最前面,绝大多数连接会立即命中,后面的直连和阻断规则形同虚设。

domainStrategy 如何影响域名与 IP 规则

routing.domainStrategy 决定路由阶段如何处理域名解析。常见值包括 AsIsIPIfNonMatchIPOnDemand。不同内核版本与客户端生成配置的方式可能存在差异,修改前应确认最终运行配置,而不是只看界面选项名称。

策略 处理重点 使用时要检查
AsIs 按原始目标信息执行域名规则,不主动为路由匹配解析 IP 依赖 IP 分流的域名连接可能无法命中预期规则
IPIfNonMatch 域名规则未匹配时,再解析 IP 并尝试 IP 规则 DNS 服务器、解析结果和最终兜底顺序
IPOnDemand 路由判断需要 IP 条件时可能触发解析 规则数量、DNS 路径和额外查询行为

若分流主要依赖 domain:geosite:,保持域名信息参与判断通常更直观。若还要让域名连接依据 geoip: 或 CIDR 归类,就要同时检查 domainStrategy 与 DNS。解析得到哪个 IP,会直接影响后续 IP 规则结果。

路由 DNS 与应用自身的解析行为也需要区分。部分连接直接提交 IP,内核看不到原始域名,此时域名规则无法命中,只能依靠 IP、端口等条件。部分应用提交域名,则可以先参与 domain 或 geosite 判断。排错时应查看日志中的目标形式,不要仅凭浏览器地址栏推断内核收到的一定是域名。

三组常用规则组合

组合一:局域网直连,其余走代理

这组结构适合需要保留本地设备访问,同时让其余 TCP、UDP 流量进入代理出站的配置。第一条先接住私有地址,第二条作为最终兜底。

{
  "domainStrategy": "IPIfNonMatch",
  "rules": [
    {
      "type": "field",
      "ip": [
        "geoip:private"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "network": "tcp,udp",
      "outboundTag": "proxy"
    }
  ]
}

启用前确认代理出站能够处理需要的网络类型,并检查本地 DNS、局域网域名与私有 IP 的对应关系。如果内部服务通过自定义域名访问,可以额外添加一条内部域名直连规则,放在最终兜底之前。

组合二:常用集合直连,剩余流量走代理

这组结构先保护私有网络,再让 geosite 和 geoip 集合直连,最后把未匹配连接交给代理。它适合以区域集合为基础的分流,但实际效果依赖数据文件和 DNS 解析结果。

{
  "domainStrategy": "IPIfNonMatch",
  "rules": [
    {
      "type": "field",
      "ip": [
        "geoip:private"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "domain": [
        "geosite:cn"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "ip": [
        "geoip:cn"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "network": "tcp,udp",
      "outboundTag": "proxy"
    }
  ]
}

若某个域名被 geosite 集合覆盖但需要代理,可在 geosite:cn 前添加精确代理条目。若把例外放在集合之后,它会被前面的直连规则截住。

组合三:阻断类别、保留例外、其余按集合分流

更完整的结构可以先放必须访问的例外,再处理阻断类别,然后执行直连集合与代理兜底。例外放在阻断规则之前,表示它拥有更高优先级。

{
  "domainStrategy": "IPIfNonMatch",
  "rules": [
    {
      "type": "field",
      "domain": [
        "full:required.example.com"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "domain": [
        "geosite:category-ads-all"
      ],
      "outboundTag": "block"
    },
    {
      "type": "field",
      "ip": [
        "geoip:private"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "domain": [
        "geosite:cn"
      ],
      "outboundTag": "direct"
    },
    {
      "type": "field",
      "network": "tcp,udp",
      "outboundTag": "proxy"
    }
  ]
}

示例中的域名仅用于说明结构,使用时应换成真实目标。整段路由配置也必须嵌入完整配置的 routing 对象中,不能把片段单独当作可运行配置。若客户端提供图形化规则编辑器,应按相同顺序逐条创建,并在保存后查看生成结果。

在 v2rayN、v2rayNG 与 v2flyNG 中落地

v2rayN 桌面端通常通过路由设置、规则集或自定义配置管理分流。不同版本的界面名称可能调整,但检查方法一致:先确认当前选中的路由模式,再确认规则绑定到正在使用的配置,最后重启相关内核并查看日志。只在编辑窗口保存,而没有切换到对应规则方案,运行结果不会变化。

v2rayNG 使用 Xray 内核时,可通过客户端提供的路由选项应用常见规则。v2flyNG 使用 v2fly 内核时,规则语义仍围绕域名、IP、端口和出站标签展开,但可用字段应以当前内核实际支持内容为准。导入订阅通常更新服务器节点信息,不应默认它会替用户合并所有本地自定义分流。

调整规则前建议先复制当前可用配置,随后每次只改一个变量。例如先增加一个 full: 域名规则并验证,再添加 geosite 集合,最后调整 domainStrategy。一次加入几十条规则后若连接异常,很难判断是 JSON 结构、标签名称、数据文件还是匹配顺序造成的。

规则不生效时按这个顺序检查

  1. 检查配置是否真正启用。确认客户端当前运行的是刚才修改的路由方案,而不是另一个节点配置或默认规则。
  2. 检查 JSON 与字段位置。rules 应位于 routing 对象中,字符串转义、逗号和方括号必须完整。
  3. 检查出站标签。outboundTag 与完整配置中的标签要逐字一致,大小写也不能混用。
  4. 检查前置规则。查看目标是否已经被更早的 domain、IP、端口或通用网络规则命中。
  5. 检查目标是域名还是 IP。若应用直接连接 IP,任何 domain 与 geosite 规则都无法从该连接恢复出原始域名。
  6. 检查 DNS 和 domainStrategy。需要 IP 二次判断时,确认路由阶段能够取得解析结果。
  7. 检查数据文件。geosite 与 geoip 条目依赖当前加载的数据内容和类别名称。
  8. 查看运行日志。重点找配置解析错误、找不到出站标签、数据加载失败以及实际选中的出站。

测试时应选择可重复的目标,并清理应用自身的连接复用影响。已经建立的长连接通常不会因为规则刚修改就立刻重新选路。保存配置后重启内核,再重新发起连接,结果更容易判断。域名解析缓存也可能保留旧地址,涉及 geoip 或 CIDR 时尤其要考虑这一点。

写规则时保留一条清晰的决策链

稳定的路由配置不取决于规则数量,而取决于每一层是否有清楚边界。精确域名负责例外,domain: 负责整站,geosite 负责批量域名,CIDR 与 geoip 负责网络地址,最终兜底负责剩余连接。把窄范围规则放前面,把宽范围规则放后面,能减少大多数优先级错误。

配置完成后,用“目标是什么、先命中哪条、交给哪个出站”三个问题逐条检查。只要这条决策链能够从日志和配置中对应起来,后续增加 VMess、VLESS 节点或更新订阅时,也能快速判断问题位于节点连接还是本地分流。

下载v2rayN