适合已经完成节点导入、希望精确控制直连、代理与拦截流量的用户。读完可区分完整域名、根域名、关键词、CIDR 与 geosite 分类,理解从上到下的首次命中规则,并能用一套带兜底项的配置完成验证。
路由规则到底处理什么
路由模块的职责
V2Ray 或 Xray 的路由模块不负责改变节点协议,也不会提升节点本身的带宽。它接收连接的目标信息,再决定把这条连接交给哪个出站。常见出站标签是 proxy、direct 与 block,分别表示交给代理节点、直接连接或拒绝连接。标签名称可以自定义,但规则里的 outboundTag 必须与出站配置中的 tag 完全一致,包括大小写。
规则可以读取的信息
一次请求能够提供的匹配信息不只域名。目标地址可能还包含 IP、端口、网络类型,部分客户端也能提供进程名或入站标签。本文集中处理最容易混淆的三类条件:domain、ip 与 geosite。其中 geosite 实际写在 domain 数组内,它引用的是预先整理的域名分类,而不是一种独立的规则字段。
路由判断的核心是“从上到下,首次命中”。核心依次读取规则列表,一旦某条规则的全部条件成立,就使用这条规则指定的出站,不再继续检查后面的规则。因此,同一个域名同时属于广告分类和地区分类时,放在前面的拦截规则会先于后面的直连规则生效。
| 规则条件 | 读取的信息 | 典型用途 | 关键限制 |
|---|---|---|---|
domain |
请求目标域名 | 指定站点直连或代理 | 目标最初只有 IP 时无法匹配 |
geosite: |
域名分类数据 | 按地区或用途批量分流 | 依赖本地分类数据文件 |
ip |
目标 IP 或解析结果 | 内网、地区 IP 与网段分流 | 域名请求是否解析受策略控制 |
port |
目标端口 | 限定 53、80、443 等端口 | 与同条规则其他字段按“并且”计算 |
domain 与 geosite 的写法差异
domain 数组支持多种前缀。最稳妥的做法不是把所有地址都写成普通字符串,而是先确认需要匹配精确主机、整个根域名,还是名称中带有某段字符的站点。匹配范围写得过宽,会让无关域名一起进入同一个出站;写得过窄,则可能漏掉静态资源、接口和登录子域名。
完整域名匹配
- 写法
- full:api.example.com
- 命中
- api.example.com
- 不命中
- www.example.com
- 范围
- 单一主机名
适合只调整一个接口域名,不影响同站其他子域名。
根域名匹配
- 写法
- domain:example.com
- 命中
- example.com
- 同时命中
- cdn.example.com
- 范围
- 根域名及子域名
适合整站统一走同一出站,是手写规则最常用的形式。
关键词匹配
- 写法
- example
- 方式
- 字符串包含
- 范围
- 所有含该片段的域名
- 风险
- 容易扩大命中范围
只在确实需要模糊匹配时使用,短词应先检查误命中。
分类列表匹配
- 写法
- geosite:cn
- 来源
- 本地域名分类数据
- 方式
- 批量匹配条目
- 维护
- 随数据文件更新
适合大范围分流,但自定义域名仍应放在分类规则之前。
regexp: 可使用正则表达式,例如 regexp:^([a-z0-9-]+\.)*example\.com$。它可以描述更复杂的主机名结构,但维护成本高于 domain:。如果目标只是覆盖根域名和所有子域名,直接写 domain:example.com 更清楚,也更不容易因为转义错误导致规则失效。
geosite:cn 表示引用名为 cn 的域名分类,geosite:category-ads-all 常用于匹配广告相关域名。分类内容来自客户端使用的数据文件,规则本身只保存分类名。核心升级后如果日志提示分类不存在,应同步检查 geosite 数据是否完整、分类名称是否受当前数据版本支持。
{
"type": "field",
"domain": [
"full:api.example.com",
"domain:static.example.com",
"geosite:category-ads-all"
],
"outboundTag": "block"
}
ip、CIDR 与 domainStrategy 怎样配合
ip 字段可以写单个地址、CIDR 网段或 geoip 分类。CIDR 中斜杠后的数字表示网络前缀长度,例如 192.168.0.0/16 覆盖从 192.168.0.0 到 192.168.255.255 的地址;10.0.0.0/8 覆盖整个 10 开头的私有网段。需要处理家庭路由器、存储设备和局域网服务时,直接使用 geoip:private 通常比逐条罗列网段更省事。
域名请求能否进入 IP 规则,取决于路由的 domainStrategy。设为 AsIs 时,路由模块按原始目标判断,域名不会为了 IP 匹配而主动解析;设为 IPIfNonMatch 时,域名规则没有命中后再解析 IP,并继续尝试 IP 规则;设为 IPOnDemand 时,匹配过程遇到需要目标 IP 的规则便可能触发解析。
- 只按域名分流:选择
AsIs,避免路由阶段产生额外解析动作。 - 域名优先、IP 补漏:选择
IPIfNonMatch,先让手写域名与 geosite 分类决定去向。 - 前置规则依赖 IP:再考虑
IPOnDemand,并确认 DNS 配置能返回可用结果。 - 局域网必须直连:把
geoip:private规则放在地区 IP 规则和最终代理兜底之前。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": [
"geoip:private",
"192.168.0.0/16",
"10.0.0.0/8"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"geoip:cn"
],
"outboundTag": "direct"
}
]
}
}
一个常见错误是在同一条规则里同时写 domain:example.com 和 geoip:cn,原意是“域名或地区 IP 任一命中就直连”,实际却变成“域名属于 example.com,并且解析结果属于该 IP 分类才直连”。要表达“或者”,应拆成两条规则,并让它们指向相同的 outboundTag。
结论:域名规则在前,IP 规则负责补漏
先用 full、domain 与 geosite 表达明确意图,再把 geoip 和 CIDR 放到后面。采用 IPIfNonMatch 后,未命中域名规则的请求才进入 IP 判断,规则顺序更容易预测。
匹配优先级与可直接套用的规则顺序
规则优先级不由 domain、ip 或 geosite 的类型决定,也不存在“精确规则自动高于分类规则”的机制。唯一可靠的优先级就是数组顺序。自定义例外应放在批量分类前,拦截规则应放在可能覆盖它的直连或代理分类前,最终再加入覆盖 TCP 与 UDP 的兜底规则。
下面的示例按“自定义直连、广告拦截、私有地址直连、地区域名直连、地区 IP 直连、其余代理”排列。实际使用前,应确认出站标签确实叫 direct、block 和 proxy。如果订阅模板使用其他标签,只替换标签值,不要随意改变条件顺序。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"full:portal.example.com",
"domain:intranet.example"
],
"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",
"ip": [
"geoip:cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
| 顺序 | 规则用途 | 放在这里的原因 |
|---|---|---|
| 1 | 手写例外 | 覆盖后续分类的默认决定 |
| 2 | 明确拦截 | 避免被地区直连分类提前接走 |
| 3 | 私有地址 | 保证路由器和局域网设备直接访问 |
| 4 | 地区域名 | 优先按域名分类判断,减少解析依赖 |
| 5 | 地区 IP | 处理没有域名或域名未分类的目标 |
| 6 | 最终兜底 | 给未命中连接一个确定出口 |
兜底规则不是每套核心配置都必须手写,因为未命中连接还可能进入默认出站;但显式兜底更便于阅读和迁移。迁移到另一份配置时,看到最后一条就能确定未分类流量的去向,不必再猜测出站数组中哪个项目排在第一位。
结论:例外必须写在分类前面
如果某个站点需要强制代理,就把它的 full 或 domain 规则放在 geosite:cn 之前;放在后面时,前面的分类一旦命中,核心不会继续读取这条例外。
在 v2rayN 中录入并验证规则
以 v2rayN 7.12.x 的桌面界面为例,先打开「设置」→「路由设置」,复制当前正在使用的规则集,再编辑副本。复制而不是直接覆盖,便于出现解析错误时立即切回原规则。不同小版本的按钮位置可能调整,但需要核对的字段仍是规则顺序、域名列表、IP 列表、目标端口和出站标签。
录入完成后选择新规则集并重启核心。随后打开「设置」→「参数设置」,确认本地监听端口。常见本地端口是 10808,但应以当前界面显示值为准;端口被修改后,测试命令也要同步替换。若系统代理已经开启,可以分别访问一条自定义直连域名、一条代理域名和一个局域网地址,观察三类请求是否走向预期出站。
- 准备 4 类测试目标:自定义例外、geosite 分类、IP 网段与未分类域名。
- 每类连续测试 3 次,共记录 12 条请求,排除缓存或偶发解析失败。
- 在实时日志中核对目标地址、命中的出站标签和失败原因。
- 修改规则后重启核心,不要用旧连接判断新规则是否生效。
- 测试局域网时直接填写设备 IP,例如
192.168.1.1,确认它命中 private 直连规则。
curl --proxy socks5h://127.0.0.1:10808 https://example.com
curl --proxy socks5h://127.0.0.1:10808 https://www.example.org
socks5h 中的 h 表示让代理端处理域名解析,这有助于让核心看到原始域名并执行 domain 或 geosite 规则。如果改用先在本地解析、再把 IP 交给代理的测试方式,日志可能只出现目标 IP,此时 domain 规则自然无法命中。
常见异常与定位方法
规则看起来正确但结果不符,通常不是语法本身的问题,而是规则没有被当前配置启用、目标信息与预期不同,或更靠前的规则已经命中。排查时不要反复交换全部规则,应先把问题缩小到一个目标域名,并从日志确认核心实际接收到的是域名还是 IP。
写了 domain 规则为什么没有命中?
先查看日志中的目标是否已经变成 IP。若测试工具在本地完成了解析,改用能把域名交给代理的方式;同时确认该规则位于 geosite 分类和最终兜底之前。
geosite 分类提示找不到怎么办?
检查当前核心读取的数据目录与 geosite 数据文件,再确认分类名拼写。更新核心后应同步更新对应数据,随后重启核心重新加载。
内网站点被送进代理怎么办?
在代理兜底前加入 geoip:private 直连规则;若使用自定义网段,再补充实际 CIDR,例如 172.16.0.0/12,并检查前面是否有更宽的强制代理规则。
同一条规则写 domain 和 ip 更准确吗?
只有确实要求两个条件同时成立时才这样写。想表达域名或 IP 任一命中,应拆成两条相邻规则,并让两条规则使用相同的出站标签。
规则保存后网页仍走旧出口?
先确认新规则集已选中,再重启核心并建立新连接。浏览器连接复用会保留旧出口,关闭相关页面后重新打开再看日志。
最后做一次顺序检查:手写例外是否位于分类之前,拦截规则是否早于大范围直连,private 是否早于代理兜底,domainStrategy 是否符合域名优先的设计。只要这四项能够从配置中直接读出来,后续添加规则时就不容易破坏已有分流。
- 先写单一目标的
full:规则,确认出站标签有效。 - 再扩大为
domain:,验证根域名与两个子域名。 - 加入 geosite 分类,并把自定义例外保留在分类之前。
- 最后启用 geoip、CIDR 和 TCP/UDP 兜底,逐层观察日志。