适合已经能正常使用 v2rayN、v2rayNG 或 v2flyNG,希望进一步控制直连、代理与阻断流量的用户。重点包括 domain、full、regexp、geosite、CIDR、geoip 的准确含义,多条件规则的组合方式,以及从特殊规则到兜底规则的排列方法。
路由规则实际处理什么
V2Ray 路由不是在多个节点之间测试速度,而是根据连接的目标信息选择一个出站。应用发起连接后,核心会读取目标域名或目标 IP、目标端口、网络类型、入站标签等字段,再从 routing.rules 第一条开始检查。首条满足全部条件的规则决定 outboundTag,后面的规则不再参与这次连接。
因此,路由配置必须先定义可用的出站标签。例如代理出站标记为 proxy,自由连接标记为 direct,阻断出站标记为 block。规则里的标签只负责引用,拼写需要与 outbounds 中的 tag 完全一致,大小写也不能混用。
一条 type: field 规则可以同时出现多个字段。同一字段数组中的值采用“任一命中”逻辑,例如 domain 数组列出三个域名时,命中其中一个即可;不同字段之间采用“同时满足”逻辑,例如一条规则同时写了 domain 和 port,目标必须既符合域名条件,也落在指定端口范围内。
| 规则字段 | 读取的信息 | 示例 | 组合关系 |
|---|---|---|---|
domain |
目标域名 | full:api.example.com |
数组内部任一命中 |
ip |
目标 IP 或解析结果 | 10.0.0.0/8 |
数组内部任一命中 |
port |
目标端口 | 53、80-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.net、cdn-example.org 都可能被纳入。已知完整域名时优先使用 full:;需要覆盖主域和子域时使用 domain:,这样比宽泛关键字更容易检查。
regexp: 中的表达式还要经过 JSON 字符串转义。正则本身的 \. 在 JSON 中应写成 \\.。如果直接少写一层反斜线,配置可能无法解析,或者表达式含义与预期不同。下面的规则只让指定接口域名及一组图片子域使用代理:
{
"type": "field",
"domain": [
"full:api.example.com",
"regexp:^img[0-9]+\\.example\\.com$"
],
"outboundTag": "proxy"
}
geosite 不是在线查询服务,而是从本地数据文件读取分类。常见写法包括 geosite:cn、geosite:private 和 geosite:category-ads-all。某个分类是否存在、具体包含哪些域名,取决于客户端当前使用的数据文件。复制规则时如果日志提示分类不存在,应先更新 Geo 数据,再确认分类名称,而不是反复修改出站节点。
full::范围最窄,适合一个确定主机名。domain::覆盖主域与子域,适合常规站点分流。regexp::表达能力强,适合有规律的动态子域。geosite::一次引用一组域名,适合分类规则。- 无前缀关键字:匹配范围较宽,维护大型规则时应谨慎使用。
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/8、172.16.0.0/12 和 192.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 的规则承接其余连接。兜底规则不能放在中间,否则其后的规则永远没有机会处理相同网络类型。
- 第一层:特定域名、特定 IP、特定端口等明确例外。
- 第二层:广告分类或需要阻断的目标。
- 第三层:局域网、私有地址和明确要求直连的站点。
- 第四层:区域域名与区域 IP 分类。
- 第五层:需要代理的指定域名或分类。
- 最后一层:覆盖
tcp,udp的兜底出站。
下面是一份便于继续扩展的组织示例。它先阻断广告分类,再直连私有地址和指定站点,随后处理区域分类,最终将其他 TCP、UDP 连接交给代理。示例中的 proxy、direct、block 必须替换为当前完整配置里真实存在的出站标签。
{
"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"
}
]
}
}
同一条规则里同时写 domain 和 ip 往往不是“二选一”,而是要求两个字段共同满足。若目标是“某域名或某 IP 都直连”,应拆成两条规则并使用相同的 outboundTag。这是自定义路由中最常见的逻辑误区之一。
结论:先拆规则,再调整顺序
当一条规则包含多个不同字段而始终无法命中,先将 domain、ip、port 拆成独立规则测试;确认单项有效后,再决定是否需要用“同时满足”的方式合并。
在客户端中落地与验证
桌面端 v2rayN 7.x 可先打开「设置」→「路由设置」,复制现有路由方案后再修改,避免直接覆盖正在使用的方案。编辑完成后保存并选中该方案,然后重启核心。若需要核对最终生成的内容,可通过「设置」→「查看配置文件」查看实际传给核心的 JSON,重点搜索 routing、rules 与 outboundTag。
安卓端 v2rayNG 与 v2flyNG 的界面入口会随版本调整,但验证原则相同:先确认当前配置已启用自定义路由,再检查预定义规则、域名策略与应用层代理设置是否互相覆盖。订阅更新通常只更新服务器配置,不应假设它会保留每一种客户端自定义路由方案;修改前保存规则文本更便于迁移。
- 先用
full:写一个确定域名,并将它指向容易识别的出站。 - 重启核心后访问该域名,查看连接日志中的目标与出站标签。
- 再测试一个不在规则中的域名,确认兜底规则正常生效。
- 访问局域网地址,例如
192.168.1.1:80,确认私有地址走直连。 - 最后加入
geosite与geoip分类,避免一次导入大量规则后难以定位问题。
测试端口条件时,需要区分本地代理监听端口和目标端口。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: 表达例外,再用 geosite、geoip 承载分类,最后保留一条可读的兜底规则。每次修改只增加一类条件,并通过日志确认实际命中的规则与出站。
当规则数量增长时,可以按“阻断、私有网络、强制直连、分类直连、强制代理、兜底代理”的顺序分组。即使客户端界面允许拖动,也应保留一份格式化 JSON 作为参考,记录 domainStrategy、出站标签和依赖的 Geo 分类。这样在 v2rayN、v2rayNG 或 v2flyNG 之间迁移思路时,不会把界面选项误当成核心语法。
- 确认每个
outboundTag都能在outbounds中找到。 - 确认精确例外位于分类规则之前。
- 确认
geoip规则与domainStrategy配合使用。 - 确认不同字段是“同时满足”,数组内部才是“任一命中”。
- 确认
network: tcp,udp的兜底规则位于最后。 - 确认正则在 JSON 中完成反斜线转义。
- 确认 Geo 数据包含配置引用的分类名称。