V2Ray 配置文件 JSON 结构逐段解析:inbounds、outbounds 与 routing 各管什么
以一份真实结构的配置为样本,逐段拆解 inbounds 入站、outbounds 出站与 routing 路由三大区块的字段含义与相互关系,帮助读者看懂并手动微调自己的配置。
一份 V2Ray JSON 配置不是按执行顺序排列的脚本,而是一张链路声明表。应用流量先进入某个入站,由路由规则读取域名、目标地址、端口或入站标签,再选择一个出站发送。DNS、日志和策略区块为这条主链提供解析、观测与行为控制。读配置时如果只盯着服务器地址,很容易漏掉真正决定流量走向的标签关系。
适合已经能导入订阅、但看不懂生成配置的读者;全文从顶层骨架开始,依次检查入站监听、代理与直连出站、路由匹配顺序、DNS 配合方式,并给出可直接用于审阅配置的字段清单。
先建立整条链路:JSON 区块不是彼此独立
V2Ray 核心读取配置后,会创建监听端口、出站处理器和路由器。以本机浏览器为例,浏览器把请求交给本地 SOCKS 或 HTTP 代理端口;入站接收连接并识别目标;routing 从上到下匹配规则;命中的 outboundTag 指向代理、直连或阻断出站。没有命中规则时,通常落到 outbounds 数组中的第一个出站,因此数组顺序本身也有含义。
下面的骨架省略了服务器身份字段,但保留了区块之间的连接点。重点观察 inbound 的 tag、routing.rules 中的 inboundTag 与 outboundTag,以及 outbounds 中对应的 tag。标签只是配置内部名称,可以自定义;引用处必须逐字一致,并且大小写不能混用。
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"]
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vmess",
"settings": {}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
结论:先追标签,再读协议细节
遇到“规则写了但没有分流”时,先核对 inboundTag、outboundTag 与实际 tag 是否闭合,再检查域名和 IP 条件;这比先改传输参数更容易定位问题。
inbounds:谁在监听,哪些流量能够进入核心
inbounds 是入站数组,每个对象代表一个接收入口。桌面代理最常见的是 SOCKS、HTTP 或由客户端组合管理的本地入口。listen 决定监听地址,port 决定端口,protocol 决定入口怎样解释连接,settings 保存协议专属选项。若 listen 为 127.0.0.1,只有本机程序能够访问;改为 0.0.0.0 会监听全部网络接口,配置前需要明确局域网访问范围和系统防火墙规则。
SOCKS 入站
- tag
- socks-in
- listen
- 127.0.0.1
- port
- 10808
- protocol
- socks
- udp
- true
适合浏览器、终端工具或支持 SOCKS5 的应用显式连接。
HTTP 入站
- tag
- http-in
- listen
- 127.0.0.1
- port
- 10809
- protocol
- http
- timeout
- 300
适合读取系统 HTTP 代理设置的桌面程序。
tag 不负责改变协议,它只为 routing 和日志提供稳定引用。一个配置可以同时定义多个入站,并让不同入口执行不同策略。例如 socks-in 默认走代理,http-in 只访问内网;此时路由规则可通过 inboundTag 区分两类连接,而不必根据来源程序猜测。
sniffing 用于从连接初期的数据中恢复目标域名。浏览器先把域名解析为 IP 后再连接时,路由器可能只能看到 IP;启用 sniffing 并设置 destOverride 后,核心有机会从 HTTP 请求或 TLS 握手中取得域名,使 domain 规则参与匹配。它不是 DNS 解析器,也不会自动修复所有域名分流问题。应用采用无法识别的封装时,路由仍可能只看到地址。
{
"tag": "http-in",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {
"timeout": 300
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
- 端口占用:启动失败并出现监听错误时,先确认 10808 或 10809 是否已被另一个进程占用。
- 代理类型:应用填写的 SOCKS5、HTTP 类型必须与对应入站协议一致,不能只看端口数字。
- UDP 开关:SOCKS 入站需要处理 UDP 时,将 settings.udp 设为 true,同时确认出站与传输链路支持目标流量。
- 局域网共享:不要只修改 listen;还要检查客户端中的局域网连接选项、系统防火墙和访问控制范围。
outbounds:代理、直连与阻断如何定义
outbounds 是出口数组。代理出站负责把流量封装到远端链路,freedom 出站让核心直接访问目标,blackhole 出站用于终止命中的连接。routing 并不保存服务器连接参数,它只返回一个 outboundTag;真正的地址、端口、用户身份、传输方式与安全层都在对应出站内。
VMess 代理出站
- tag
- proxy
- protocol
- vmess
- address
- 节点域名
- port
- 443
- network
- ws
- security
- tls
用户参数位于 settings,传输与安全层位于 streamSettings。
本地控制出站
- direct
- freedom
- block
- blackhole
- 引用方式
- outboundTag
- 默认出口
- 数组首项
私有地址通常直连,明确需要终止的目标可交给 block。
以 VMess 为例,settings.vnext 是服务器列表,users 保存 id、alterId 与 security 等用户参数;streamSettings 则描述 TCP、WebSocket 等承载方式以及 TLS 设置。服务器端要求的传输方式、路径、主机名和端口必须成组一致。只把 network 从 tcp 改成 ws,而没有同步 path 与服务端入口,不会得到兼容链路。
{
"tag": "proxy",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "server.example",
"port": 443,
"users": [
{
"id": "订阅提供的用户标识",
"alterId": 0,
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"wsSettings": {
"path": "/gateway"
},
"tlsSettings": {
"serverName": "server.example"
}
}
}
VLESS 常见于 Xray 内核配置,外层仍能看到 tag、protocol、settings 和 streamSettings,但 flow、Reality 等字段属于对应内核和链路能力,不能机械复制进任意 V2Ray 配置。v2rayN 使用的核心可由客户端设置决定,v2rayNG 使用 Xray 内核,v2flyNG 使用 v2fly 内核。阅读订阅生成内容时,先确认当前核心,再查该核心支持的字段边界。
- 先确认 outbounds 中代理项的 tag 是否为 routing 实际引用的名称。
- 再核对 address、port 与用户身份字段,避免把本地监听端口误当远端端口。
- 随后核对 network、security、path、serverName 等传输层字段是否成组对应。
- 最后查看日志中的握手、超时或连接拒绝信息,不用连续随机切换参数。
结论:连通性错误按层处理
本地端口无法连接先查 inbound;远端超时先查 outbound 地址与网络;单类域名走错出口再查 routing。按层定位可以避免一次改动多个变量。
routing:匹配条件、规则顺序与默认出口
routing.rules 是有顺序的规则数组。常用 type 为 field,条件可以包含 domain、ip、port、network、inboundTag 和 protocol 等。一个规则内部写入多个不同类型条件时,通常需要同时满足;同一字段中的多个值则作为候选集合。规则按声明顺序检查,先命中的规则决定 outboundTag,后续规则不再覆盖它。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["domain:intranet.example"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:category-ads-all"],
"outboundTag": "block"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
这组规则先放行私有地址,再放行指定内部域名,然后终止命中的目标,最后用 tcp,udp 作为兜底代理。若把兜底代理放到第一条,它会先捕获绝大多数连接,后面的直连和阻断规则便失去执行机会。审查分流配置时,不仅要问“有没有这条规则”,还要问“它前面是否已有更宽的条件”。
| 字段 | 匹配对象 | 典型写法 | 检查重点 |
|---|---|---|---|
| domain | 目标域名 | domain:example.com | 是否能取得域名,是否被前置规则截获 |
| ip | 目标地址 | geoip:private | domainStrategy 是否触发解析 |
| port | 目标端口 | 53 或 80-443 | 这里不是本地入站端口 |
| network | 传输类型 | tcp,udp | 宽条件应靠后作为兜底 |
| inboundTag | 流量入口 | socks-in | 必须与 inbounds 的 tag 一致 |
domainStrategy 决定路由阶段怎样处理域名与 IP 条件。AsIs 尽量按原始目标匹配,不为 IP 规则主动解析域名;IPIfNonMatch 会先尝试域名规则,在没有命中时解析地址并继续匹配 IP 规则;IPOnDemand 在可能需要 IP 匹配时更积极地解析。选择它不是速度开关,而是规则语义选择。配置包含 geoip:private 等 IP 规则,同时入口经常提供域名时,IPIfNonMatch 是较容易理解的起点。
DNS 与路由怎样配合:解析结果不等于最终出口
dns 区块定义核心可使用的解析服务器、静态 hosts 和查询策略,routing 决定连接交给哪个出站。两者有关联,但不是同一个步骤。应用如果自行发出 DNS 查询,查询会先作为普通网络流量进入核心;应用如果已经给出目标 IP,域名规则能否参与匹配还取决于 sniffing 和连接中是否存在可识别的域名信息。
{
"dns": {
"hosts": {
"domain:internal.example": "192.168.10.20"
},
"servers": [
{
"address": "223.5.5.5",
"port": 53,
"domains": ["geosite:cn"]
},
"1.1.1.1"
],
"queryStrategy": "UseIP"
},
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"port": 53,
"network": "udp",
"outboundTag": "proxy"
}
]
}
}
样例把 UDP 53 端口流量交给 proxy,但它并不覆盖所有解析形态:应用可能使用 TCP 53,也可能使用加密的 HTTPS 连接完成解析。更稳妥的排查方式是先确认请求究竟由系统解析器、应用自身还是核心 DNS 发出,再决定路由规则需要匹配端口、域名还是特定入站。仅增加一个 DNS 地址,无法自动保证全部请求采用同一出口。
- 域名规则完全不命中时,检查入站是否启用 sniffing,以及日志中目标显示为域名还是 IP。
- 私有域名应直连但被代理时,把明确的内部域名与 geoip:private 规则放在宽泛代理规则之前。
- 修改 DNS 后结果没有变化时,重启相关应用并清理系统解析缓存,再进行单一目标测试。
- 出现解析成功但连接超时时,DNS 已完成工作,下一步应检查 routing 选择和 outbound 链路。
手动微调前的检查顺序:避免改完被覆盖
客户端通常把订阅节点、全局参数和路由设置合成为运行配置。v2rayN 7.13.x 的通用参数可从「设置」→「参数设置」进入,先记录本地端口、核心类型、系统代理模式与 DNS 相关选项;路由调整应在客户端提供的路由设置中完成。v2rayNG 1.10.x 可从「设置」检查本地代理、DNS 与分流相关项目。版本界面可能调整文字,但审查顺序不变:先确认配置来源,再确认生成结果。
- 保留可恢复副本:导出当前客户端配置或复制准备修改的独立 JSON,记录原有模式和生效范围。
- 验证 JSON 语法:检查逗号、引号、方括号与花括号。JSON 不接受行尾注释,也不能在数组最后一项后保留多余逗号。
- 检查标签闭环:列出全部 inbound tag、outbound tag 和规则引用,确认不存在拼写差异。
- 一次只改一层:端口问题只改入站,节点问题只改出站,分流问题只改规则顺序和条件。
- 建立最小测试集:分别测试一个应直连目标、一个应代理目标和一个明确阻断目标,并记录三次结果。
- 回到客户端持久设置:确认临时修改有效后,把等价设置写回 v2rayN、v2rayNG 或 v2flyNG 的正式配置入口。
JSON 能启动,但所有网站都走代理,哪里最可能写错?
先看 routing.rules 的第一条是否已经用 network: tcp,udp 或过宽的 domain 条件捕获全部连接。把私有地址、内部域名和明确直连规则移到兜底代理规则之前,再重启核心测试。
改了 outbounds 的服务器地址,切换节点后为什么恢复了?
当前文件很可能由订阅节点动态生成。应编辑客户端保存的节点资料,或在节点列表中更新对应服务器字段;不要把运行目录中的临时 JSON 当作长期配置源。
规则写了 domain,日志里却只有 IP,怎么处理?
检查对应 inbound 的 sniffing.enabled 是否为 true,并确认 destOverride 包含实际流量类型。仍只有 IP 时,再检查应用是否提前解析且连接中没有可恢复的域名。
10808 能连接,10809 连接失败,是节点坏了吗?
先核对 inbounds 是否同时声明两个端口,以及 10809 对应的 protocol 是否为 http。单个本地端口失败通常属于监听或端口占用问题,不能直接归因于远端节点。
配置中同时有 proxy、direct、block,怎样确认实际用了哪一个?
把日志级别临时设为 info,分别访问预设的代理、直连和阻断目标,结合目标地址与报错结果检查规则。完成后恢复 warning,并保留三类测试目标供后续回归。
读懂 V2Ray 配置的关键不是记住所有字段,而是把每次连接还原为“从哪个入站进入、携带什么目标、命中哪条规则、落到哪个出站”。inbounds 解决接收问题,outbounds 解决发送问题,routing 解决选择问题,DNS 与日志补充解析和观测。沿着这条链检查,即使配置由订阅和客户端自动生成,也能快速找到端口冲突、标签断链、规则遮挡和传输参数不一致的位置。