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

系统梳理 domain、full、regexp、ip、geosite、geoip 等规则写法,说明规则自上而下的匹配顺序与常见冲突,附可直接套用的示例片段。

本文速览

自定义分流先看规则顺序,再看匹配条件,最后检查 DNS 策略。本文面向已能正常连接节点、需要补充站点例外规则的用户,说明 V2Ray 与 Xray 常见 field 路由写法,以及如何在 v2rayN 中落地和验证。示例使用保留的演示域名与文档地址,不代表实际网站分类。

一、路由规则先判断条件,再选择出站

路由不是节点连接参数。VMess、VLESS 等协议负责连接服务端;路由负责决定一条已进入内核的请求交给哪个出站。v2rayN 是配置界面,实际执行规则的是当前运行的内核。下文使用 V2Ray/Xray 的 JSON 语法,不能原样粘贴到其他配置格式的编辑器。

一条常见规则包含 type: "field"、匹配字段和 outboundTag。标签必须对应现有出站的 tag。把标签写成 proxy 并不会自动创建代理节点,写成 direct 也不会自动创建直连出站。客户端生成的标签可能不同,修改前应核对实际配置。

53
传统 DNS 常用目标端口
443
HTTPS 常用目标端口
/32
IPv4 单地址 CIDR 前缀

这些端口是请求的目标端口,不是客户端的本地监听端口。例如下面这条规则只将目标端口为 443、域名属于 example.com 的请求交给代理出站,并不覆盖该域名的所有连接。

{
  "type": "field",
  "domain": ["domain:example.com"],
  "port": "443",
  "outboundTag": "proxy"
}

二、domain、full、regexp:域名匹配的边界

需要覆盖主域名和全部子域名时,用 domain:;只允许某个完整主机名时,用 full:。不要因为规则名都含有“域名”,就把两者视为相同。域名字段里填写的是主机名,不是网页地址,不应带协议、路径或查询参数。

条目写法匹配范围容易混淆的边界
domain:example.comexample.com 及其子域名,例如 api.example.com不匹配 notexample.com,也不匹配 example.com.test
full:example.com仅 example.com不匹配 www.example.com
example域名中包含该字符串可能命中 unrelated-example.test,不适合精确站点例外
regexp:^api[0-9]+\.example\.com$例如 api1.example.com、api25.example.com需要首尾锚点;写入 JSON 时反斜杠还要转义

正则表达式只在确有模式需求时使用。下例在 JSON 字符串中将反斜杠写成两次,因此内核收到的正则才包含用于匹配字面圆点的 \.。如果界面字段接收的是原始规则文本,而不是 JSON 字符串,就不需要这一层 JSON 转义。

{
  "type": "field",
  "domain": [
    "full:login.example.com",
    "regexp:^api[0-9]+\\.example\\.com$"
  ],
  "outboundTag": "proxy"
}

结论:单站例外先用 full

只想修正一个登录主机时,先添加完整主机名规则并验证;确认全部子域名都需要同一出口后,再扩大为 domain 规则,避免连带改变静态资源和其他业务的出口。

三、ip、geoip、geosite:地址与域名集合分开写

ip 是 JSON 字段,geoip: 是可放入该字段数组的集合引用;geosite: 则放在 domain 数组内。两类集合依赖内核能够读取的对应数据文件。集合名称及其内容由数据文件决定,不是内核根据名称实时生成的结果。

{
  "type": "field",
  "domain": ["geosite:cn"],
  "outboundTag": "direct"
}
{
  "type": "field",
  "ip": [
    "192.0.2.15/32",
    "2001:db8::15/128",
    "geoip:private",
    "geoip:cn"
  ],
  "outboundTag": "direct"
}

上面的 192.0.2.15 与 2001:db8::15 是文档示例地址,实际使用时替换成目标服务的地址。IPv4 的 /32 和 IPv6 的 /128 都表示单个地址;网段前缀越短,覆盖范围通常越大。不要为了解决一个地址的访问问题,直接加入覆盖整片网络的大网段。

四、匹配优先级:例外规则必须排在宽规则前面

内核不会自动比较“完整域名比域名集合更精确”。规则按 rules 数组从上往下执行。如果第一条已用 domain:example.com 直连,那么后面的 full:api.example.com 代理规则没有机会覆盖它。正确顺序是先放例外,再放覆盖面更大的集合,最后放兜底。

下面是可合并到现有配置的 routing 片段,不是完整客户端配置。前提是现有 outbounds 中已经有 proxy 和 direct 两个标签,并且具备所引用的数据集合。若实际标签不同,应先统一标签,不能只复制规则而忽略出站。

{
  "routing": {
    "domainStrategy": "IPOnDemand",
    "rules": [
      {
        "type": "field",
        "domain": ["full:api.example.com"],
        "outboundTag": "proxy"
      },
      {
        "type": "field",
        "domain": ["domain:example.com", "geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:private", "geoip:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}
测试目标首次命中预期出站
api.example.com:443第 1 条完整域名例外proxy
www.example.com:443第 2 条主域及子域规则direct
192.168.1.20:80第 3 条私有地址集合direct
未命中上述集合的公网目标第 4 条 TCP/UDP 兜底proxy

表格是配置推演,不是联网测速结果。演示域名不保证运行实际服务,验证网页时应换成已知可用的目标。如果移除最后一条兜底规则,未匹配请求通常使用配置中第一个出站;因此不能脱离完整配置,笼统地说“未命中一定代理”或“未命中一定直连”。

五、domainStrategy:为什么 IP 规则没有生效

请求进入内核时,目标可能是域名,也可能已经是 IP。只有地址的请求,不会因为你添加了域名规则就自动恢复成原始域名。反过来,只有域名的请求,要匹配 ip 条件,通常需要路由解析策略提供地址。这正是 domainStrategy 需要单独检查的原因。

策略路由阶段行为配置注意点
AsIs不为路由匹配主动将目标域名解析为 IP目标本来就是 IP 时仍可匹配 IP 规则;不等于出站永不解析域名
IPIfNonMatch域名首轮没有规则匹配后,尝试解析并再次匹配首轮若已命中无条件兜底,就不会触发这次补充解析
IPOnDemand匹配过程遇到需要 IP 的规则时,尝试解析目标域名可能增加 DNS 查询;应同时考虑解析延迟与 DNS 出口

上一节使用 IPOnDemand,是为了让第三条地址集合规则能在最后的兜底之前参与判断。如果直接改成 IPIfNonMatch,域名请求可能先命中第四条宽泛规则,导致预期的地址分流没有发生。这不是 geoip 写法错误,而是解析触发时机不同。

结论:先确定需要哪一种信息

按站点分流先保证请求携带域名;按解析地址分流再选择解析策略。DNS 服务器、DNS 查询如何出站,以及嗅探是否覆盖目标,应分别核对,不能靠切换一个 domainStrategy 同时解决。

六、在 v2rayN 中应用与验证

普通使用者优先通过路由设置界面维护规则。v2rayN 会生成运行配置,直接修改临时生成的 JSON,可能在重启服务或切换节点后被覆盖。下面以带有「设置」→「路由设置」入口的桌面界面为例;不同界面版本的按钮位置可能变化,但规则顺序和出站映射仍需逐项检查。

  1. 保留原配置

    打开「设置」→「路由设置」,记录当前使用的规则集和域名解析策略。修改前备份已有配置;不要直接清空默认规则集。

  2. 添加单条规则

    在目标规则集中添加一个完整域名条件,例如 full:api.example.com,选择代理出站。界面域名输入框只填写规则条目,不粘贴整个 routing 对象。

  3. 调整规则顺序

    把这条例外移动到对应的 domain:、geosite: 或其他宽泛规则之前。保存后确认主界面当前选中的就是刚修改的规则集。

  4. 重新建立连接

    重启服务或重新加载配置,再关闭目标网页的旧连接并重新访问。已有连接一般不会因为规则改动而自动迁移到另一出站。

  5. 核对运行日志

    查看核心日志中的目标主机、目标端口及出站标签。先用一个已知可用的网站验证,再扩大规则范围;日志级别不足时,临时提高到 info 或 debug,完成后恢复。

验证时至少做三组请求:例外主机、同主域下的普通主机、局域网资源。前两组检查域名规则的边界,第三组检查私有地址直连是否被前面的宽泛代理规则遮挡。日志未出现请求时,先检查应用是否经过当前代理入口,而不是继续修改路由表达式。

七、常见规则冲突的快速解答

full 已经写了,为什么还是直连?

先检查它前面是否存在覆盖该域名的 domain:、geosite: 或全流量规则。把完整域名例外移到宽规则之前,保存并用新连接测试;同时核对这条规则选择的出站标签。

把 domain 和 ip 放一起怎么反而不匹配?

它们在一条 field 规则中是同时满足的条件。需要“域名或地址任一命中”时,拆成两条具有相同出站的规则;只有确实需要限定两项条件时才保留合写。

geosite:cn 存在,为什么有些站点仍走代理?

先确认目标实际请求的主机名,例如页面引用的资源域名可能不同。再检查前置规则、数据文件是否加载以及集合是否包含该域名。可以先添加一条明确的 full: 规则验证,并通过访问日志确认实际出站。

设置 port 443 就能匹配所有网页吗?

不能。它只限制目标端口;传统 HTTP 可能使用 80,其他服务也可能使用自定义端口。HTTPS 还可能走 TCP 或 UDP,若额外写了 network: "tcp",就不会匹配 UDP 请求。

订阅更新后,自定义规则还会有效吗?

节点订阅与路由规则属于不同配置内容。更新后检查当前规则集是否仍被选中,以及代理出站是否还指向有效节点。不要把订阅地址当作路由配置,也不要把路由 JSON 粘贴到订阅地址输入框。

排查顺序保持固定:确认请求进入内核,确认域名或地址信息可用,检查第一条命中的规则,再检查出站本身是否能连接。每次只改一类条件,才能分清是规则边界、DNS 策略,还是节点网络造成了结果变化。

下载v2rayN按平台选择安装包