本文速览

适合已经能正常使用 v2rayN、v2rayNG 或 v2flyNG,希望进一步控制直连、代理与阻断流量的用户。重点包括 domain、full、regexp、geosite、CIDR、geoip 的准确含义,多条件规则的组合方式,以及从特殊规则到兜底规则的排列方法。

路由规则实际处理什么

V2Ray 路由不是在多个节点之间测试速度,而是根据连接的目标信息选择一个出站。应用发起连接后,核心会读取目标域名或目标 IP、目标端口、网络类型、入站标签等字段,再从 routing.rules 第一条开始检查。首条满足全部条件的规则决定 outboundTag,后面的规则不再参与这次连接。

因此,路由配置必须先定义可用的出站标签。例如代理出站标记为 proxy,自由连接标记为 direct,阻断出站标记为 block。规则里的标签只负责引用,拼写需要与 outbounds 中的 tag 完全一致,大小写也不能混用。

应用发起请求读取目标信息逐条匹配规则选择出站标签建立连接

一条 type: field 规则可以同时出现多个字段。同一字段数组中的值采用“任一命中”逻辑,例如 domain 数组列出三个域名时,命中其中一个即可;不同字段之间采用“同时满足”逻辑,例如一条规则同时写了 domainport,目标必须既符合域名条件,也落在指定端口范围内。

规则字段 读取的信息 示例 组合关系
domain 目标域名 full:api.example.com 数组内部任一命中
ip 目标 IP 或解析结果 10.0.0.0/8 数组内部任一命中
port 目标端口 5380-443 与其他字段同时满足
network 传输层网络 tcp,udp 与其他字段同时满足
inboundTag 连接来自哪个入站 socks-in 与其他字段同时满足

domain、full、regexp 与 geosite

domain 字段承载域名条件,但数组里的每个字符串还可以使用不同前缀。没有前缀的普通字符串按关键字匹配,范围最宽;domain: 按域名及其子域名匹配;full: 只匹配完整域名;regexp: 使用正则表达式;geosite: 则引用本地规则数据中的域名分类。

精确域名

写法
full:api.example.com
命中
api.example.com
不命中
www.example.com

适合单独控制接口域名、更新域名或固定服务入口。

域名与子域

写法
domain:example.com
命中
example.com
同时命中
cdn.example.com

常用于将一个主域及其全部子域交给同一出站。

正则匹配

写法
regexp:^img[0-9]+\.example\.com$
命中
img12.example.com
代价
匹配开销较高

仅在前缀、后缀和规则集无法表达目标时使用。

域名分类

写法
geosite:cn
数据来源
本地 geosite 数据文件
更新方式
随规则数据更新

适合覆盖大量域名,但分类内容取决于本地数据版本。

普通关键字写法容易扩大命中范围。例如数组项写成 example 时,只要域名中包含这段字符就可能命中,example.netcdn-example.org 都可能被纳入。已知完整域名时优先使用 full:;需要覆盖主域和子域时使用 domain:,这样比宽泛关键字更容易检查。

regexp: 中的表达式还要经过 JSON 字符串转义。正则本身的 \. 在 JSON 中应写成 \\.。如果直接少写一层反斜线,配置可能无法解析,或者表达式含义与预期不同。下面的规则只让指定接口域名及一组图片子域使用代理:

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

geosite 不是在线查询服务,而是从本地数据文件读取分类。常见写法包括 geosite:cngeosite:privategeosite:category-ads-all。某个分类是否存在、具体包含哪些域名,取决于客户端当前使用的数据文件。复制规则时如果日志提示分类不存在,应先更新 Geo 数据,再确认分类名称,而不是反复修改出站节点。

ip、CIDR、geoip 与 domainStrategy

ip 字段可以写单个地址、CIDR 网段或 geoip: 分类。单个 IPv4 地址可以写成 192.0.2.10,网段可以写成 192.168.0.0/16;IPv6 同样使用 CIDR,例如 fd00::/8。私有网络通常用 geoip:private 统一处理,避免逐条列出 10.0.0.0/8172.16.0.0/12192.168.0.0/16

IP 规则能否匹配域名请求,与 routing.domainStrategy 直接相关。浏览器访问域名时,核心最初拿到的目标可能仍是域名。如果策略为 AsIs,路由阶段不会为了 IP 规则主动解析该域名,因此 geoip:cn 不应被当成域名分类的替代品。

domainStrategy 处理方式 适用重点
AsIs 按原始目标匹配,不为路由主动解析域名 以 domain、geosite 规则为主
IPIfNonMatch 域名规则未命中后,再解析 IP 并尝试 IP 规则 域名规则优先,geoip 用于补充
IPOnDemand 匹配过程中遇到需要 IP 信息的规则时解析目标 强依赖 IP 条件的规则结构

多数“域名分类直连、IP 分类补充”的配置可从 IPIfNonMatch 开始。这样先检查 geosite:cn,未命中时再通过解析结果检查 geoip:cn。如果 DNS 返回多个地址,实际连接与路由解析结果还会受到 DNS 配置、缓存和地址选择影响,因此不要仅凭一次解析结果判断整条规则失效。

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

结论:域名分类与 IP 分类不能互换

需要按站点归类时先写 geosite,需要按解析后的网络位置补充时再写 geoip;同时把 domainStrategy 设为与这套顺序一致的策略。

匹配优先级与规则排列方法

V2Ray 不会给 full:geosite:geoip: 自动分配全局优先级。所谓“精确规则优先”,实际要靠配置者把精确规则放在前面。只要前面的规则已经命中并选定出站,后面更精确的条件也不会覆盖结果。

最稳定的排列方式是“例外在前、分类居中、兜底在后”。先放必须阻断或必须直连的精确目标,再放私有网络和区域分类,随后放需要代理的分类,最后用仅包含 network: tcp,udp 的规则承接其余连接。兜底规则不能放在中间,否则其后的规则永远没有机会处理相同网络类型。

  1. 第一层:特定域名、特定 IP、特定端口等明确例外。
  2. 第二层:广告分类或需要阻断的目标。
  3. 第三层:局域网、私有地址和明确要求直连的站点。
  4. 第四层:区域域名与区域 IP 分类。
  5. 第五层:需要代理的指定域名或分类。
  6. 最后一层:覆盖 tcp,udp 的兜底出站。

下面是一份便于继续扩展的组织示例。它先阻断广告分类,再直连私有地址和指定站点,随后处理区域分类,最终将其他 TCP、UDP 连接交给代理。示例中的 proxydirectblock 必须替换为当前完整配置里真实存在的出站标签。

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

同一条规则里同时写 domainip 往往不是“二选一”,而是要求两个字段共同满足。若目标是“某域名或某 IP 都直连”,应拆成两条规则并使用相同的 outboundTag。这是自定义路由中最常见的逻辑误区之一。

结论:先拆规则,再调整顺序

当一条规则包含多个不同字段而始终无法命中,先将 domain、ip、port 拆成独立规则测试;确认单项有效后,再决定是否需要用“同时满足”的方式合并。

在客户端中落地与验证

桌面端 v2rayN 7.x 可先打开「设置」→「路由设置」,复制现有路由方案后再修改,避免直接覆盖正在使用的方案。编辑完成后保存并选中该方案,然后重启核心。若需要核对最终生成的内容,可通过「设置」→「查看配置文件」查看实际传给核心的 JSON,重点搜索 routingrulesoutboundTag

安卓端 v2rayNG 与 v2flyNG 的界面入口会随版本调整,但验证原则相同:先确认当前配置已启用自定义路由,再检查预定义规则、域名策略与应用层代理设置是否互相覆盖。订阅更新通常只更新服务器配置,不应假设它会保留每一种客户端自定义路由方案;修改前保存规则文本更便于迁移。

测试端口条件时,需要区分本地代理监听端口和目标端口。v2rayN 常见本地 SOCKS 监听端口为 10808,它属于入站端口;路由规则里的 port: 443 指远端目标端口。把 10808 写进目标端口规则,通常不会得到“所有浏览器流量”的效果。

若修改后所有网页都无法连接,先回退到只有一条兜底规则的最小配置,再逐条恢复。核心日志中出现 failed to parse 时检查 JSON 逗号、引号和正则转义;出现找不到 geosite 或 geoip 分类时更新对应数据文件;连接建立但出站不符时,优先检查规则顺序与标签拼写。

写了 full 规则,为什么还是走兜底代理?

先确认日志中的目标仍是域名而不是应用提前解析出的 IP,再检查完整域名、端口条件和出站标签。若应用直接连接 IP,单独的 full: 规则不会命中。

geosite:cn 和 geoip:cn 应该只留一个吗?

两者处理的信息不同。可先用 geosite:cn 匹配域名,再在 IPIfNonMatch 下使用 geoip:cn 补充按解析地址判断的连接。

把 direct 放在第一条为什么代理规则失效?

检查第一条是否写了覆盖全部连接的 network: tcp,udp。这种规则属于兜底规则,应移到列表末尾,否则后续同网络类型规则无法命中。

同一规则写 domain 和 port 是什么关系?

两个字段必须同时满足。例如 domain:example.com 配合 port:443,只处理该主域及子域发往目标端口 443 的连接,不包括目标端口 80。

可维护规则的最终检查

一份可维护的路由配置不需要堆叠大量重复条目。优先使用明确的 full:domain: 表达例外,再用 geositegeoip 承载分类,最后保留一条可读的兜底规则。每次修改只增加一类条件,并通过日志确认实际命中的规则与出站。

当规则数量增长时,可以按“阻断、私有网络、强制直连、分类直连、强制代理、兜底代理”的顺序分组。即使客户端界面允许拖动,也应保留一份格式化 JSON 作为参考,记录 domainStrategy、出站标签和依赖的 Geo 分类。这样在 v2rayN、v2rayNG 或 v2flyNG 之间迁移思路时,不会把界面选项误当成核心语法。