本文面向准备编辑 Xray 路由规则的用户。从域名与 IP 的输入差异开始,解释规则语法、字段组合和解析策略,再给出可核对的 routing 片段。读完可以判断一条连接为什么走直连、代理或阻断,以及修改规则后应该查看哪些日志。示例使用保留测试域名,不涉及真实服务凭据。
路由输入与出站标签
Xray 的路由负责选择出站,不负责替应用创建请求。应用连接先进入 inbounds,路由读取目标地址、端口和网络类型等信息,再把连接交给对应的 outbounds。v2rayN 是客户端界面;本文代码描述的是 Xray 内核的 JSON 配置,不能直接当作订阅链接导入。
每条规则的 outboundTag 必须对应现有出站的 tag。下面使用的 direct、proxy、block 都是人为约定的标签,不是写上名称就会自动出现的功能。通常分别绑定直连出站、已配置的代理出站和阻断出站。
- 有域名:通过 SOCKS 或 HTTP 代理提交域名时,路由通常可以直接检查域名规则。
- 只有 IP:应用先完成解析,再向代理提交 IP 时,域名规则没有可直接比较的域名。
- 启用嗅探:内核可能从受支持的握手信息中提取域名;是否覆盖目标或仅供路由使用,由嗅探配置决定。
- 没有规则命中:在常规 Xray 配置中使用第一个出站。不要把这一隐式行为误认为固定的“默认代理”。
domain、full 与 regexp 的区别
域名匹配内容放在规则的 domain 数组中。这里的 domain 既是字段名,也可以是数组元素中的匹配前缀。字段名说明“检查域名”,前缀说明“怎样比较”。下面的 example.test 是保留测试域名,适合说明语法,不代表可直接访问的服务。
| 数组元素 | 匹配方式 | 边界说明 |
|---|---|---|
full:api.example.test | 完整域名匹配 | 匹配该主机,不包含其子域名。 |
domain:example.test | 域名及子域名匹配 | 包含根域名和 api.example.test,不包含 notexample.test。 |
example | 普通字符串匹配 | 按子串匹配,范围通常比域名后缀匹配更宽。 |
regexp:^api[0-9]+\\.example\\.test$ | 正则表达式匹配 | 这是 JSON 字符串写法,反斜杠需要转义。 |
geosite:cn | 域名集合匹配 | 读取本地域名数据文件中的指定集合。 |
只想让一个接口走代理,优先使用 full:。需要覆盖整个域名树,使用 domain:。不要把 *.example.test 当成通用通配符写入普通域名条目;需要通配效果时,应选择域名后缀匹配或明确的正则表达式。
{
"type": "field",
"domain": [
"full:api.example.test",
"regexp:^edge[0-9]+\\.example\\.test$"
],
"outboundTag": "proxy"
}
上例两个数组元素是“或”的关系,任意一个命中即可。正则表达式中的点必须表达为字面点;在 JSON 中因此写成 \\.。首尾的 ^ 和 $ 限制匹配范围,避免意外匹配带有额外前缀或后缀的主机名。
ip、geoip 与 geosite 数据集
ip 字段用于检查目标 IP,可以填写单个地址、CIDR 网段或 geoip: 集合。域名集合放在 domain 中,IP 集合放在 ip 中。geosite 与 geoip 不是在线查询服务,也不能互换字段。
{
"type": "field",
"ip": [
"192.168.0.0/16",
"10.0.0.0/8",
"fc00::/7",
"geoip:private"
],
"outboundTag": "direct"
}
这段示例显式列出几个私有网段,并使用 geoip:private 集合补充覆盖。部分范围会重叠,这是为了对照语法;实际配置可以按所用数据文件的内容精简。192.168.0.0/16 表示一个网段,不是只匹配 192.168.0.0 这一个地址。
geosite.dat提供域名集合;geoip.dat提供 IP 集合。文件必须能被当前核心从其资源路径读取。geosite:cn和geoip:cn分别描述域名集合与地址集合,二者结果不必一致。- 集合名称、属性筛选和覆盖范围取决于实际数据文件。不能根据分类名称推断某个网站必然在其中。
- 修改规则后若核心无法启动,先查日志中是否存在文件读取失败或集合不存在的错误,不要立即更换节点。
匹配优先级与字段组合
routing.rules 按数组顺序检查,第一条满足条件的规则决定出站。规则越具体,不代表内核会自动把它排得越靠前。位于前面的宽泛规则可能提前结束匹配,使后面的例外规则没有机会生效。
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": ["full:api.example.test"],
"outboundTag": "proxy"
},
{
"type": "field",
"domain": ["domain:example.test"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
在这个片段中,api.example.test 走代理,www.example.test 走直连,其余 TCP、UDP 连接由最后一条规则交给代理。若把第二条移到第一条之前,接口域名会先命中域名树规则,改走直连。
| 组合位置 | 逻辑关系 | 实际含义 |
|---|---|---|
同一 domain 数组的多个条目 | 或 | 命中其中任意一项即可满足该字段。 |
同一 ip 数组的多个网段 | 或 | 地址落入任意一个网段即可满足该字段。 |
同一规则的 domain 与 port | 且 | 域名和端口必须同时满足。 |
同一规则的 domain 与 ip | 且 | 不是域名或 IP 二选一;IP 条件还依赖目标地址信息与解析策略。 |
结论:把例外放在集合规则之前
先写单个主机的特殊处理,再写域名树和分类集合,最后写兜底规则。若目标是“域名命中或 IP 命中就直连”,应拆成两条规则,而不是把两种字段塞进同一条。
domainStrategy 如何影响 IP 匹配
routing.domainStrategy 决定路由阶段是否为域名补充 IP 信息。它不是修改规则顺序的开关,也不是指定 DNS 服务器地址的字段。即使配置中存在 dns 段,路由也不会因此自动对每个域名执行 IP 匹配。
| 策略 | 路由阶段的行为 | 需要注意 |
|---|---|---|
AsIs | 不为了路由匹配主动解析域名。 | 目标本来就是 IP 时,仍可匹配 IP 规则。 |
IPIfNonMatch | 域名未匹配到规则时,再尝试解析并进行包含 IP 条件的匹配。 | 第一轮若已命中宽泛兜底,就不会因未命中而触发解析。 |
IPOnDemand | 遇到需要 IP 信息的规则时,尝试解析域名后继续判断。 | 靠前的 IP 规则可能增加解析依赖,并影响后续域名规则能否被执行。 |
一个常见误区是:选择 IPIfNonMatch,在前面写 geoip:cn,最后再写覆盖全部 TCP、UDP 的代理规则,就期待所有域名先按地区 IP 分流。对于域名目标,第一轮可能直接命中最后的代理规则;既然已经匹配,就没有“未匹配后解析”的机会。
- 希望主要按域名集合分流:先配置清晰的域名规则,并确认仅有 IP 的请求如何处理。
- 希望域名无规则可匹配时才按 IP 判断:使用
IPIfNonMatch,同时检查是否有提前命中的通用规则。 - 希望靠前的 IP 条件也参与域名请求的决策:评估
IPOnDemand,并确认 DNS 返回结果与规则顺序符合预期。
路由解析得到的 IP 不应简单等同于最终建立连接时使用的地址。出站是否继续使用域名、在哪里解析,还受所用协议及出站设置影响。排查时应把“路由为什么选中这个标签”与“连接最终去了哪里”分开验证。
按端口建立最小验证用例
不要一次导入几十条分类规则再观察网页是否打开。先使用一个明确的入站端口、一条带端口限制的域名规则和可识别的出站标签,验证匹配链路。下面三个数字是测试配置中的明确参数,不是所有客户端版本的默认值。
{
"type": "field",
"domain": ["full:api.example.test"],
"port": "443",
"network": "tcp",
"outboundTag": "proxy"
}
该规则只匹配目标域名、目标端口 443 和 TCP 同时成立的连接。它不匹配同一主机的 80 端口,也不匹配 UDP 443。port 检查的是目标端口,不是本地 SOCKS 监听的 10808。浏览器若使用基于 UDP 的传输,不能用这条 TCP 规则推断其结果。
- 备份当前可用配置,确认核心已读取新的路由配置,而不是仍运行旧进程。
- 核对本地入站确实监听
127.0.0.1:10808;若使用其他端口,以实际配置为准。 - 在测试环境为保留域名准备解析或嗅探输入。未准备测试服务时,只检查核心能否加载规则,不把访问失败当成路由失败。
- 需要比较 DNS 行为时临时提高日志级别,重复一次请求,核对接收目标、DNS 查询与出站标签;测试完成后恢复原日志级别。
- 每次只调整一项:先改规则顺序,再改
domainStrategy,最后引入数据集。保留每一步的结果,避免多项变化互相掩盖。
v2rayN 路由排错问答
在 v2rayN 中调整路由后,还要核对当前选用的路由配置与内核类型。本文使用 Xray 的字段语义;界面中的路由编辑项可能由客户端转换后写入生成配置,不应把整段 JSON 随意粘贴到只接受域名条目的输入框。
加了 full 规则,为什么还是走原来的出站?
先把该规则移到宽泛域名集合和兜底规则之前,再重新加载配置。查看日志中的目标是否仍是域名;若目标只有 IP,就检查应用是否自行解析,以及入站嗅探是否确实提供了可用域名。
geosite 规则保存后,核心为什么启动失败?
查看核心启动日志,分别确认数据文件能否读取、集合名称是否存在,以及规则是否放进了正确字段。先用一条 full: 规则验证路由,再恢复集合规则,可以区分语法问题与数据文件问题。
配置了 IPIfNonMatch,为什么没有看到预期的 DNS 查询?
检查第一轮是否已命中域名规则或 network: tcp,udp 兜底。已有匹配就不满足“未匹配”的触发条件。需要按 IP 条件提前判断时,再评估 IPOnDemand,不要仅靠移动 IP 规则猜测结果。
同一规则写 domain 和 ip,为什么命中变少了?
这两个字段需要同时满足。若原意是域名集合或地址集合任意命中即可直连,把它们拆成两条规则,并保持相同的 outboundTag。随后分别用域名目标与 IP 目标测试。
修改生成配置后,重启客户端又恢复了,怎么办?
自动生成的配置可能在切换节点或重启核心时重建。应在客户端提供的路由配置入口保存规则,或使用其支持的自定义配置方式。重启后再次核对核心实际加载的内容,不以编辑器中曾经保存成功作为生效依据。
最终核对顺序应固定为:输入目标是什么、规则是否满足、哪条规则最先命中、标签是否存在、出站能否连接。网页打开只能证明一次访问完成,不能单独证明分流正确。保留最小测试规则与对应日志,比同时切换多个路由模式更容易定位问题。