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

从一份完整 config.json 出发,逐段讲清入站监听、出站 tag 与路由规则的匹配顺序,以及三者如何通过 tag 串联。

本文速览

适合已经能导入节点、但还分不清配置字段作用的读者。先用一份只包含本地监听、直连与阻断的完整配置建立请求路径,再拆解端口、tag 和规则顺序,最后说明如何接入实际代理出站,以及怎样避免修改 v2rayN 临时生成文件后被覆盖。

1. config.json 的请求路径

config.json 是内核读取的配置文件,不等同于订阅链接,也不等同于客户端设置文件。订阅通常提供节点信息;客户端根据节点、路由和本地监听设置生成内核配置。理解这层关系,才能判断某个修改应放在节点编辑、路由设置,还是自定义配置中。

应用请求 入站接收 路由匹配 出站连接 目标服务

inbounds 回答“请求从哪里进入”,outbounds 回答“请求怎样离开”,routing 回答“这次请求选哪条出口”。浏览器必须先把请求送到本地代理端口,路由规则才有机会处理;只修改路由,不会自动让所有应用接入代理。

本文采用 V2Ray 常见的 JSON 配置结构。V2Fly 与 Xray 有共同字段,但协议能力、字段选项与命令行参数仍需按实际内核区分。v2rayNG 使用 Xray 内核,v2flyNG 使用 V2Fly 内核;v2rayN 桌面端则应先确认当前配置实际调用的内核,不能仅凭客户端名称判断。

2. 完整配置:双入站、直连与阻断

下面是一份结构完整的教学配置:SOCKS 监听 127.0.0.1:10808,HTTP 监听 127.0.0.1:10809。访问示例域名 example.org 及其子域名时阻断,其他请求默认直连。它不包含远程代理节点,因此不是可用于远程代理的节点配置。

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    },
    {
      "tag": "http-in",
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http",
      "settings": {}
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "blocked",
      "protocol": "blackhole",
      "settings": {}
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "domain": [
          "domain:example.org"
        ],
        "outboundTag": "blocked"
      },
      {
        "type": "field",
        "ip": [
          "10.0.0.0/8",
          "172.16.0.0/12",
          "192.168.0.0/16",
          "127.0.0.0/8",
          "::1/128"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "inboundTag": [
          "http-in"
        ],
        "outboundTag": "direct"
      }
    ]
  }
}

这是严格 JSON:键名和字符串使用双引号,没有注释,也没有末尾多余逗号。数组可包含多个对象,但每个对象必须遵守对应协议的字段定义。不要把界面上显示的“节点名称”直接当成内核配置键,也不要给顶层随意增加一个 subscription 字段;订阅管理属于客户端功能。

3. inbounds:监听地址、端口与入站 tag

listen 是本机绑定地址,不是远程节点地址;port 是应用连接的本地端口,不是服务端端口。将监听限制为 127.0.0.1,表示只接受本机 IPv4 回环连接。改为所有网卡监听会扩大可访问范围,涉及局域网访问控制,不能当作连接失败时的通用修复方法。

SOCKS 入站

protocol
socks
listen
127.0.0.1
port
10808
tag
socks-in

应用必须使用 SOCKS 协议接入;UDP 还取决于应用和后续出站链路。

HTTP 入站

protocol
http
listen
127.0.0.1
port
10809
tag
http-in

HTTPS 目标通常通过 CONNECT 隧道访问,不需要把入站协议改为 https。

tag 是配置内部的标识。入站的 socks-in 可以被路由规则的 inboundTag 引用;它不会决定协议,也不会自动生成一个同名出站。建议每个入站和出站分别使用唯一、稳定的 tag,修改名称时同步检查所有引用。

示例中的 udp: true 仅表示 SOCKS 入站允许 UDP。应用需要支持 SOCKS UDP ASSOCIATE,出站也需要承载该流量;开启这一项并不等于系统全部 UDP 都会经过内核,更不等于普通 HTTP 系统代理可以捕获游戏流量。

4. outbounds:协议实现与默认出口

示例的 freedom 表示直连,blackhole 表示阻断;direct 和 blocked 只是人为指定的 tag。把 direct 改名为 office-direct 不会改变其行为,但所有引用它的 outboundTag 都必须一起修改。

字段或位置示例值实际作用
protocolfreedom选择直连出站实现
tagdirect供路由规则引用的标识
settings{}该出站协议的配置对象
数组第一项direct没有规则命中时使用的默认出站

普通路由规则全部未命中时,内核使用 outbounds 数组的第一项。示例将直连放在首位,因此没有匹配到阻断或指定入站规则的流量仍会直连。若把阻断出站移动到首位,大量未命中请求就会被阻断;这不是“节点突然失效”,而是默认出口改变。

判断顺序:先找默认出口,再读例外规则

检查配置时先圈出 outbounds[0].tag,再逐条核对 routing.rules。这样能先确定未命中流量的去向,避免只盯着某一条域名规则而遗漏整体行为。

5. routing:顺序匹配、字段组合与域名解析

routing.rules 按数组顺序从上到下检查,第一条命中的规则决定出口,不会继续寻找“更精确”的后续规则。通常将具体例外放在前面,将范围更大的规则放在后面。如果第一条就是匹配全部 TCP 和 UDP 的出口规则,后面的域名规则便没有机会生效。

  1. 先查目标域名。当请求携带 example.org 或其子域名时,第一条规则选择 blocked。domain: 匹配该域名及子域名;只匹配一个完整域名时可使用 full:。
  2. 再查目标 IP。示例列出的私有地址和回环地址走 direct。这是地址段匹配,不会因为域名最终可能解析到私有地址就必然触发。
  3. 再查来源入站。第三条规则匹配来自 http-in 的请求,并选择直连。但此前已命中域名阻断的请求不会再执行这一条。
  4. 最后使用默认出站。来自 socks-in、且未命中前两条的请求,使用数组第一项 direct。

同一条规则中,不同条件字段通常需要同时满足。例如同时写入 inboundTag 和 domain,表示指定入站中的指定域名;同一个域名数组内的多个条目则是候选项。将“或”关系误写成一条含多个条件字段的规则,是分流不生效的常见原因。

domainStrategy 位于 routing 内,控制路由匹配阶段如何处理域名。AsIs 不为匹配 IP 规则而主动解析域名;IPIfNonMatch 在域名未匹配时尝试解析后再匹配;IPOnDemand 在匹配需要 IP 信息的规则时触发解析。它不是“所有 DNS 一律走代理”的开关。

6. 接入代理出站:先确认上游,再修改引用

远程代理需要真实的服务端参数。VMess、VLESS 等出站的地址、端口、身份信息和传输安全设置必须与服务端一致,不能只把 protocol 改一个名称便完成转换。对已有节点,优先通过客户端导入并检查生成配置,避免手动拼接不同内核的协议字段。

为了单独演示“新增出站再引用”的过程,下面使用一个本机 SOCKS 上游。前提是另一个独立服务确实监听 127.0.0.1:10810,并且不要求认证。此对象应加入 outbounds 数组;它只是配置片段,不是一份完整文件。

{
  "tag": "proxy",
  "protocol": "socks",
  "settings": {
    "servers": [
      {
        "address": "127.0.0.1",
        "port": 10810
      }
    ]
  }
}

7. 验证配置与 v2rayN 的保存位置

验证分成三层:JSON 能否解析、内核能否接受字段、真实请求是否符合规则。三层不能互相替代。文本格式正确并不表示引用的 tag 存在,内核启动成功也不表示系统代理已经指向正确端口。

  1. 备份原文件。保留一个能正常启动的副本,每次只修改一个类别,例如只改端口或只改路由,便于回退。
  2. 使用匹配内核检查。先运行随包内核的帮助命令,确认该版本的配置测试参数。测试工具必须与实际运行内核一致,不要用另一种内核的检查结果代替。
  3. 读取启动日志。若日志提示监听失败,先处理地址或端口;若提示配置加载失败,先核对字段类型和协议设置。定位问题时可临时将 loglevel 改为 info,排查后恢复。
  4. 发起两组明确请求。先验证直连出口,再验证阻断规则;测试时显式指定端口,避免混入其他应用的代理设置。
curl --proxy socks5h://127.0.0.1:10808 --connect-timeout 5 https://example.com/
curl --proxy socks5h://127.0.0.1:10808 --connect-timeout 5 https://example.org/
curl --proxy http://127.0.0.1:10809 --connect-timeout 5 https://example.com/

socks5h 要求把目标主机名交给代理处理,适合验证本例的域名规则。在外网可达的前提下,第一和第三条应通过直连出站尝试访问;第二条应被阻断。具体错误提示取决于内核与 curl 版本,不能仅凭某个错误码判定命中了哪条规则,应同时查看日志。Windows 若命令被终端别名接管,可显式运行 curl.exe。

在 v2rayN 中,先通过「设置」→「参数设置」核对本地监听端口,再通过「设置」→「路由设置」检查启用的路由配置;不同版本的分组或名称可能略有变化,以当前界面为准。普通节点运行时使用的配置往往由客户端重新生成,切换节点、更新订阅或重启内核后,直接修改生成文件的内容可能被覆盖。

保存位置:常用规则留在客户端设置

要长期保留端口与分流规则,应修改客户端对应设置;要完整控制一份 JSON,则使用客户端的自定义配置功能,并确认该条目调用的内核。不要同时维护一套界面规则和一份临时文件,再假设二者会自动合并。

8. 常见配置问题

节点已经选中了,为什么示例还是直连?

本例第一出站是 freedom,没有远程代理参数。客户端中选中节点,并不会自动改写一份独立运行的 JSON。先确认实际加载的文件,再检查 outbounds[0] 和命中规则的 outboundTag。

把 tag 改名后,规则为什么不工作了?

在文件中搜索旧 tag,逐个核对 outboundTag 与 inboundTag。引用需要与对应对象的 tag 完全一致,包括大小写。修改后重新测试并重启内核,不能只保存文本而继续使用旧进程。

开了系统代理,为什么某些应用仍不经过 10809?

系统代理只对遵循该设置的应用有效。先用上面的 HTTP 测试命令验证监听,再检查应用是否有独立代理设置。不要通过扩大监听地址来处理应用未使用代理的问题,两者属于不同层次。

能把订阅内容直接粘贴到 config.json 吗?

不能把任意订阅文本当成内核 JSON。先在 v2rayN 的订阅管理中导入并更新,确认节点协议与所选内核支持情况;需要研究结构时再查看客户端生成的配置,并注意隐藏地址和身份信息后再分享。

继续阅读字段定义时,可使用JSON 手册核对监听、出站与路由各段。实际排查仍按同一顺序进行:应用是否接入、入站是否监听、规则是否命中、出站是否能连接。每次只验证一层,比同时修改 DNS、端口与协议参数更容易找到原因。

v2rayN下载