本文面向需要手动调整分流的用户。先区分域名、IP 与数据集的匹配语法,再通过一组 routing 示例理解规则顺序、字段组合与 DNS 解析时机。排查时以客户端实际生成的内核配置为准,不把界面里的“直连”“代理”名称直接当成 outboundTag。
1. 路由匹配的对象与执行顺序
V2Ray 的 routing 根据连接的目标地址、目标端口、网络类型和入站标签等信息选择出站。它不是网页内容过滤器,也不按 URL 路径分流。访问同一域名下的两个不同页面,通常不会因此命中不同的域名规则。
routing.rules 按数组顺序从上到下判断。某条规则满足条件后,便按它指定的出站处理;后面的规则不会再与它比较“谁更精确”。因此,精确域名例外通常放在域名后缀规则前,具体规则放在兜底规则前。
- 规则之间:先命中的规则决定结果,不会自动按域名长度、前缀类型或网段大小排序。
- 同一字段内部:例如
domain数组中的多个条目,满足其中一个即可。 - 不同条件字段之间:例如同时填写
domain和port,必须同时满足。把domain与ip放进同一条规则,不表示“域名或者 IP”。 - 全部未命中:在未设置其他路由机制的常规配置中,使用
outbounds数组的第一个出站。这个结果不一定是直连。
2. domain、full、regexp 与 geosite 的写法
domain 是规则字段名,domain: 则是该字段内的一种匹配前缀。两者不要混淆。下面全部使用保留示例域名 example.com,用于说明语法,不代表真实服务的分流建议。
| 条目写法 | 匹配含义 | 注意事项 |
|---|---|---|
full:example.com | 只匹配这个完整域名 | 不会同时覆盖 www.example.com |
domain:example.com | 匹配自身及其子域名 | 覆盖 api.example.com,不覆盖 notexample.com |
example.com | 未加前缀时按子串匹配 | 可能匹配域名中包含此字符串的其他名称 |
regexp:^api[0-9]+\.example\.com$ | 按正则表达式匹配 | 写入 JSON 时,反斜杠需要再次转义 |
geosite:cn | 引用域名数据文件中的 cn 分类 | 分类内容取决于实际加载的数据文件 |
希望覆盖某个站点及其子域名时,优先写 domain:example.com,而不是依赖裸字符串。需要只处理一个主机名时,再用 full:。域名条目不应包含 https://、端口、路径或查询参数;这些不是该字段的输入格式。
{
"type": "field",
"domain": [
"full:status.example.com",
"domain:example.net",
"regexp:^api[0-9]+\\.example\\.com$"
],
"outboundTag": "proxy"
}
这段 JSON 中,三个域名条目是“或”的关系。正则中的 \\. 经过 JSON 解码后才成为正则所需的 \.;如果只写一条反斜杠,配置可能在 JSON 解析阶段就失败。正则应遵循内核所用的 Go 正则语法,不使用回溯引用或前后向断言。
判断:单站点规则先用 full 或 domain
只有域名结构确实需要模式表达时再用 regexp。修改后分别测试主域名、一个子域名和一个相似但无关的域名,避免把子串误匹配当成规则生效。
3. ip、geoip 与目标端口如何组合
ip 字段接受单个 IP、CIDR 网段以及 geoip: 数据集引用。IPv4 的 /32 表示一个地址;192.0.2.0/24 表示一个文档示例网段。不要把 CIDR 写入 domain 数组,也不要在 ip 数组里添加 https://。
{
"type": "field",
"ip": [
"192.0.2.0/24",
"2001:db8::/32"
],
"port": "443",
"network": "tcp",
"outboundTag": "direct"
}
这条规则只匹配目标地址位于两个示例网段之一、目标端口为 443、网络为 TCP 的连接。它不会匹配同地址的 TCP 80,也不会匹配 UDP 443。这里的 port 是目标端口,不是客户端的本地监听端口;本地入站需要按标签区分时,应使用 inboundTag。
geoip:private常用于私有及本地地址范围的分流,具体覆盖范围由所加载的数据文件决定。geoip:cn是 IP 分类引用;geosite:cn是域名分类引用,二者不可互换。- 域名分类与 IP 分类不保证结论一致。一个域名可能解析到不同地区的 CDN 地址。
- 仅写 IPv4 网段不会覆盖 IPv6 连接。双栈环境应同时检查实际使用的地址族。
4. domainStrategy 决定何时为路由解析域名
routing.domainStrategy 控制路由阶段如何处理域名目标。它不等于系统 DNS 设置,也不等于出站自身的同名或近似设置。即使路由阶段不解析,后续出站为了连接服务器仍可能需要解析地址。
| 取值 | 路由阶段行为 | 常见影响 |
|---|---|---|
AsIs | 按原始目标进行匹配,不为路由额外解析域名 | 只有域名的目标不会因此获得可供 IP 规则匹配的解析结果 |
IPIfNonMatch | 域名阶段没有规则命中时,再尝试解析并重新匹配 | 前面的域名命中或通用兜底可能使解析阶段不再触发 |
IPOnDemand | 匹配过程中遇到需要 IP 判断的规则时,尝试解析域名 | 较早的 IP 规则可能先于后面的域名规则决定结果 |
一个容易忽略的情况是:使用 IPIfNonMatch,却在末尾添加匹配所有 TCP、UDP 的规则。域名请求会直接命中这个兜底,因此不能再指望“前面的 geoip 没命中,随后自动解析再试”。如果需要域名规则优先、随后按解析 IP 分流,应一起审查解析策略和兜底方式。
域名优先,未命中再解析
- domainStrategy
- IPIfNonMatch
- 规则起始
- 明确的域名例外
- 后续条件
- 需要补充判断的 IP 规则
- 兜底检查
- 避免通用规则提前命中
确认全部规则未命中时,第一个出站正是预期的默认出站。
按规则顺序按需解析
- domainStrategy
- IPOnDemand
- 规则起始
- 需要优先保留的域名例外
- 后续条件
- IP 或 geoip 条件
- 兜底检查
- 可在 IP 判断后显式兜底
先测试 DNS 能否返回结果,再检查 IP 分类是否符合预期。
如果应用交给内核的目标本来就是 IP,路由不需要靠这项设置获得该地址。但此时域名信息可能不存在。入站的嗅探功能可以在部分协议中补充域名线索,其效果受流量类型和具体配置限制,不能认为开启后所有连接都会恢复域名。
5. 一组可核对顺序的 routing 示例
下面是配置片段,不是可单独运行的完整配置。前提是已有出站标签 proxy、direct 和 block,分别指向代理、直连和阻断出站。标签由配置作者定义,不是内核自动创建的保留名称。此例还要求可用的数据文件包含 private 分类。
{
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"type": "field",
"domain": ["full:status.example.com"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["domain:example.com"],
"outboundTag": "proxy"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"port": "6881-6889",
"outboundTag": "block"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
- 精确例外在前:
status.example.com命中第 1 条后直连,不会继续落入第 2 条的整个域名后缀规则。 - 站点规则在后:
www.example.com命中第 2 条,选择proxy。 - 内网地址优先:前两条均未命中时,私有地址可命中第 3 条。域名目标在这里可能触发按需解析。
- 端口规则不是全局禁令:第 4 条只处理此前未命中的连接。前面已命中的站点或私有地址不会再进入它。
- 显式兜底在末尾:剩余 TCP、UDP 连接命中第 5 条。这里使用
IPOnDemand,使前面的 IP 判断有机会先执行。
操作:把必须全局执行的限制移到前面
如果端口 6881–6889 必须优先阻断,应把端口规则移到域名和私有地址规则之前。调整的是数组位置,不是给规则添加一个不存在的“优先级数字”。
使用 geosite:cn 时,可按实际需求增加一条域名规则,但不要因为分类名称熟悉就直接覆盖所有例外。先确认数据文件可加载,再判断这条规则应位于精确域名例外之后、IP 规则之前还是其他位置。数据更新也可能改变分类命中结果。
6. 从客户端界面到实际生效配置的检查方法
v2rayN、v2rayNG、v2flyNG 的界面名称和路由导入方式随版本变化。排查时先记录客户端版本、内核名称和所用路由模式,再定位当前启用的规则集。不要把订阅节点中的 VMess、VLESS 连接参数当成路由规则;节点负责定义出站连接,路由负责选择它。
- 备份当前规则:保存修改前的路由内容。订阅更新通常用于更新节点,不应被当成分发本地自定义路由的通用机制。
- 确认请求进入内核:检查应用是否使用系统代理或指定的本地代理入口。未进入入站的请求,不会受这些规则控制。
- 核对生成配置:查看当前
routing.rules的实际顺序,以及outboundTag是否与outbounds[].tag完全一致。 - 应用并重新测试:保存规则后按客户端要求重新加载或重启内核,再新建连接。浏览器连接复用可能让旧连接继续沿用原来的出站。
- 检查日志:需要时临时使用
info级别,观察入站、目标和所选出站;不同内核的日志格式不同,不一定显示具体规则序号。
建议一次只改一个条件。先用 full: 验证一个明确域名能否分流,再换成 domain: 扩大范围,最后添加 geosite 或 geoip 分类。需要查找配置对象的上下文时,可配合配置参考核对入站、出站与 DNS 字段。
7. 路由规则常见问题
加了域名规则,为什么还是走原来的节点?
先查看它之前是否已有更宽泛的规则命中。临时把测试用的 full: 规则放到首位,重新加载内核并新建连接。若仍不生效,再确认请求目标是域名还是 IP,以及流量是否真正进入当前客户端。
geosite 或 geoip 提示分类找不到,应该改哪里?
检查当前内核实际使用的数据文件及其中的分类名称。geosite: 应放在 domain,geoip: 应放在 ip。先用单个域名或明确网段验证规则结构,再处理数据资源缺失,不要反复修改节点密码。
同一条规则同时填了 domain 和 ip,为什么更难命中?
两个字段需要同时满足,不是二选一。若目的只是“这个域名或这个网段都直连”,应拆成两条规则,并分别指定同一个 outboundTag。拆分后再检查域名解析策略是否允许 IP 条件参与判断。
改成 IPIfNonMatch,geoip 仍然没效果?
检查末尾是否存在 network: "tcp,udp" 这类通用匹配。它可能在域名阶段已经命中,阻止“未命中后解析”的流程。可根据需求调整为按需解析,或移除提前兜底并核对默认出站;两种改法都应重新测试域名和 IP 目标。