V2Ray 配置文件 JSON 结构解析:inbounds、outbounds 与 routing 逐段读懂

按 log、dns、inbounds、outbounds、routing 的顺序拆解客户端生成的配置文件,说明各字段的作用与相互引用关系,帮助看懂 tag 与路由规则的匹配逻辑。

本文速览

本文适合已经导入订阅、希望读懂核心配置的用户。先用一份只含本地 SOCKS 入口、直连与阻断出站的 JSON 建立结构,再逐段核对日志、DNS、端口、标签和规则顺序;读完可以定位“核心启动失败”“本地端口连不上”“规则没有命中”分别应该检查哪里。

先区分客户端设置与核心配置

v2rayN 是桌面客户端,负责管理订阅、服务器条目、路由预设及核心进程;V2Ray 或 Xray 才是读取核心配置并处理连接的程序。客户端保存的界面偏好、订阅分组数据,不等于交给核心的运行时 JSON。排查时应找本次启动实际加载的文件,而不是看到扩展名为 .json 就直接修改。

Android 上的 v2rayNG 使用 Xray 内核,v2flyNG 使用 V2Fly 内核。本文解释的是 V2Ray 常见配置结构,不能由此推断两个内核的全部字段通用。例如 REALITY 属于 Xray 的相关能力,不能把对应配置直接交给 V2Fly。即使同叫 streamSettings,具体传输名称与可用选项也应按当前内核确认。

应用连接 本地入站 规则匹配 选定出站 连接目标

这条流程是阅读主线,DNS 会在需要域名解析的环节参与,日志则记录整个过程。系统代理只影响遵循该设置的应用;配置中存在 SOCKS 入站,不代表所有应用的流量已经进入核心。入口未接通时,继续修改路由通常不会改变结果。

完整 JSON 示例:一个入口、两个出站、两条规则

下面是结构教学配置,不含远端代理服务器。它在 127.0.0.1:10808 提供 SOCKS 服务,阻断对 example.org 的精确域名请求及 TCP 25 端口请求,其余连接默认直连。不要把它当作现有订阅配置的替代品,否则原有代理出站会丢失。

{
  "log": {
    "loglevel": "warning"
  },
  "dns": {
    "servers": [
      "1.1.1.1"
    ]
  },
  "inbounds": [
    {
      "tag": "socks-local",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {
        "domainStrategy": "UseIP"
      }
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "inboundTag": [
          "socks-local"
        ],
        "domain": [
          "full:example.org"
        ],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "network": "tcp",
        "port": "25",
        "outboundTag": "block"
      }
    ]
  }
}

顶层对象的键排列顺序通常不决定处理顺序,本文只是按阅读需要排列;但数组中的顺序可能直接影响行为,尤其是 outbounds 的首项与 routing.rules 的先后。不要为了“整理格式”随意给这两个数组排序。

log:先用日志区分启动错误与连接错误

log 控制日志输出,不负责选择节点。示例只设置 loglevel,没有指定日志文件;实际输出位置取决于核心启动方式,客户端可能把输出收集到自己的日志面板。排障时先看启动后的第一条错误,再看触发访问时新增的记录。

字段或现象具体含义下一步
loglevel: warning保留警告和错误,适合正常使用时减少输出。需要更多连接信息时临时改为 info。
loglevel: debug输出更多调试细节,日志增长更快。复现一次问题后恢复原级别,分享前删除敏感信息。
address already in use监听地址与端口被其他进程占用。检查 10808 是否已由另一核心实例监听。
字段解析或配置加载错误核心尚未进入正常处理连接的阶段。检查字段拼写、数据类型及当前核心是否支持该选项。

如果核心启动即退出,先修复配置或端口冲突,不要先换 DNS。如果核心正常运行,只有某个请求失败,再检查对应目标、路由结果与连接错误。日志中可能包含访问域名、服务器地址及本地路径,不应把完整运行配置和日志直接发布到公开页面。

dns:解析服务器与路由策略不是同一个开关

dns.servers 指定核心内置 DNS 使用的解析服务器。示例中的 1.1.1.1 是普通 DNS 服务器地址,通常通过 UDP 53 查询;这里没有配置加密 DNS,也不意味着查询自动经过代理。解析服务器是否可达,需要在实际网络中验证。

最容易混淆的是两个同名字段:routing.domainStrategy 决定路由匹配阶段如何对待域名,freedom 出站里的 settings.domainStrategy 则决定直连建立连接时如何解析目标。它们处在不同对象内,枚举值和作用也不同。

路由匹配阶段

位置
routing.domainStrategy
示例值
AsIs
作用
不为路由匹配主动解析目标域名。
其他常见值
IPIfNonMatch、IPOnDemand

AsIs 不表示整个连接过程都不会发生 DNS 查询。

直连出站阶段

位置
freedom.settings.domainStrategy
示例值
UseIP
作用
通过内置 DNS 将目标域名解析为 IP 后连接。
解析来源
本例的 dns.servers

不要把路由的 IPIfNonMatch 填进这个位置。

IPIfNonMatch 会在域名未匹配到规则时尝试解析,再检查 IP 规则;IPOnDemand 会在匹配过程需要 IP 时触发解析。两者都不是“强制全部流量走代理”的设置。若配置没有 IP 规则,先保持策略简单,避免为解释一个域名规则而引入额外解析行为。

inbounds:确认应用连接到了哪个入口

inbounds 是数组,每一项描述一个接收连接的入口。本例的 listen 限定为本机回环地址,port 是数字 10808,protocol 是 socks。三个字段共同决定应用该连接到哪里、用什么协议连接。

  1. 核对监听地址:127.0.0.1 只供本机访问。将其改成 0.0.0.0 会扩大监听范围,不应为了排障直接暴露无认证入口。
  2. 核对协议:SOCKS 端口不等于 HTTP 代理端口。把只支持 HTTP 代理的程序指向本例 10808,不能据此判断节点是否可用。
  3. 核对实际端口:10808 是本文指定值,不是所有客户端的固定值。v2rayN 可在「设置」→「参数设置」中核对本地监听相关选项,最终以运行配置和日志为准。
  4. 核对 UDP:udp: true 允许此 SOCKS 入站处理 UDP,但应用仍需使用 SOCKS UDP 机制,后续出站和网络也必须支持对应流量。

tag: socks-local 是入口的内部名称,不是域名,也不是节点订阅名。它不改变监听协议,而是让其他配置可以引用这个入口。本例第一条规则的 inboundTag 写成数组,是因为一条规则可以接受多个入口标签。

"inboundTag": [
  "socks-local"
]

更改入口标签后,引用它的规则也要同步更改。只把入站的 socks-local 改成 local-socks,却保留原规则,会导致该规则无法匹配这个入口的流量。

outbounds:标签、协议与默认出站

outbounds 定义连接下一步如何发出。本例的 freedom 表示直连,blackhole 表示阻断;它们不是远端代理协议。真实订阅生成的配置可能额外出现 VMess 或 VLESS 出站,并携带服务器地址、端口、用户标识及传输参数。

项目本文示例阅读要点
tagdirect、block由规则引用的名称,大小写与拼写必须一致。
protocol: freedom直连出站从运行核心的设备直接连接目标。
protocol: blackhole阻断出站用于拒绝指定流量,不会自动改走其他出站。
VMess、VLESS本例未配置需有效服务器与认证参数,不能仅更改协议名称。
streamSettings本例不需要描述传输与安全层,需和服务端对应设置一致。

在本例这种未设置其他默认分派机制的配置中,未命中路由规则的连接使用 outbounds 的第一项,因此默认直连。把 block 移到第一项会改变兜底行为;把标签改名则不会自动改变数组顺序。

结论:先确认默认出站,再分析例外规则

打开运行配置后先记录 outbounds 第一项的 tag,再逐条检查 routing.rules 的 outboundTag;这比只搜索“proxy”更可靠,因为标签名称由配置生成方定义。

如果真实配置使用 proxy 作为代理出站标签,那么路由中的 outboundTag: proxy 必须能找到对应出站。给本例新增一条指向 proxy 的规则,并不会凭空创建代理连接;应先保留并核对客户端生成的有效代理出站。

routing:规则从上到下,条件分清“且”与“或”

routing.rules 通常按从上到下的顺序检查,命中一条规则后使用它指定的出站,不再继续寻找后面的普通规则。因此,具体规则应放在覆盖面更广的规则前面。配置中写了某条规则,不等于它一定有机会被执行。

同一条规则里的不同条件字段通常是“且”的关系,而同一字段数组内的多个候选值通常是“或”的关系。本例第一条同时要求入口为 socks-local,目标域名为 example.org,二者都满足才交给 block。

送入本地 SOCKS 的请求匹配过程结果
域名 example.org,TCP 443第一条的入口与精确域名均满足。block
域名 www.example.org,TCP 443不满足精确域名,也不是目标 25 端口。默认 direct
其他域名,TCP 25第一条不匹配,第二条匹配。block
其他域名,TCP 443两条规则都不匹配。默认 direct

上述推演以应用确实向 SOCKS 入站提交域名为前提。如果应用提前解析并只提交 IP,第一条域名规则可能无法使用。嗅探可以在部分协议中识别域名信息,但它不是必定恢复原始域名的工具;本例没有启用嗅探,应先用明确的域名请求测试规则。

配置检查步骤与常见问答

读配置时一次只改一个变量,并记录修改前后的日志。先验证核心能启动,再验证入口可达,最后确认规则与出站;把端口、DNS、标签和传输参数同时更改,会让一次成功或失败都难以解释。

  1. 检查语法与类型:端口 10808 是数字,udp 是布尔值 true,inbounds 与 outbounds 是数组。
  2. 核对所有引用:逐个查找 inboundTag、outboundTag,确认在对应入口或出站中存在同名 tag。
  3. 确认应用使用入口:测试本例时显式指定 SOCKS 地址,避免浏览器系统代理设置干扰判断。
  4. 推演路由:从第一条规则开始,对照目标域名、目标端口、网络类型与入口标签检查。
  5. 恢复客户端管理:确认原理后,把长期修改落实到客户端支持的路由或配置选项,再重新生成运行配置验证。

如果设备安装了支持 SOCKS 的 curl,可以在核心加载本例且端口未被占用的前提下运行以下命令。socks5h 要求把目标域名交给 SOCKS 服务处理;本例会因精确域名规则阻断该请求,失败是这项测试的预期结果,而不是远端代理故障。

curl --proxy socks5h://127.0.0.1:10808 --connect-timeout 10 https://example.org/

改了 JSON,重启 v2rayN 后怎么又变回去了?

运行文件可能由客户端重新生成。先保留修改记录,再到「设置」→「路由设置」检查对应规则,或使用当前版本明确支持的自定义配置入口;不要把临时运行文件当成永久设置源。

outboundTag 写了 proxy,为什么还是启动报错?

在 outbounds 数组里查找 tag 为 proxy 的项,确认没有拼写或大小写差异。如果不存在,应恢复有效的代理出站配置,而不是只给 freedom 改一个名称。

DNS 改成 1.1.1.1,为什么域名规则仍然没命中?

先检查应用是否提交了域名,再确认规则顺序与 full、domain 前缀。更换解析服务器不会自动补回应用已经丢失的域名信息,也不会改变规则优先级。

VLESS 出站能直接替换 VMess 的 protocol 字段吗?

不能。两类协议的认证字段和协议参数不同,传输与安全层也必须符合服务端配置。应重新导入正确的订阅或连接资料,再核对实际运行核心支持的字段。

阅读更多配置概念可查阅路由分流技术参考;需要从客户端界面核对解析设置时,按教程中的 DNS 设置步骤操作。核心结构读懂后,再逐项对照客户端界面,能减少把订阅、入口和路由当成同一个设置的误判。

客户端下载安装v2rayN · v2rayNG