config.json 结构逐段解析:inbounds、outbounds 与 routing 各管什么
拆开一份最小可用配置,逐段说明入站定义本地监听、出站定义远端连接、routing 决定流量走哪条出站,并解释 tag 如何把三段串成一条完整链路。
无论配置由 v2rayN 的订阅功能生成,还是由维护人员手工整理,核心结构都可以归纳为三个问题:流量从哪里进入、准备从哪里离开、匹配条件决定走哪一条出口。理解这三个问题后,排查“端口能连接但网页打不开”“直连域名仍然走代理”“拦截规则没有命中”等故障会更直接。
本文适合已经能导入订阅、希望继续理解底层配置的用户。阅读后可以识别 inbounds、outbounds、routing 与 tag 的职责,读懂一份包含 SOCKS 入站、VMess 代理出口、直连出口和拦截出口的配置,并按日志顺序定位规则未命中、端口冲突与出站引用错误。
先建立完整流量链:入站、匹配、出站
应用不会直接“进入 routing”。浏览器或其他程序先把请求发送到本机监听端口,inbounds 接收连接并生成可供核心处理的目标信息;routing 再读取目标域名、目标 IP、端口、网络类型与入站标签;匹配成功后,规则里的 outboundTag 指向某个 outbounds 项。没有规则命中时,通常使用 outbounds 数组中的第一项作为默认出口,因此数组顺序同样属于配置逻辑。
可以把 config.json 看成一张有向连接图,而不是一组互不相关的参数。inbounds 中的 tag 用于标记流量来源,outbounds 中的 tag 用于命名出口,routing.rules 则引用这些名称完成连接。tag 本身不传输数据,也不会自动建立代理链;它只是核心内部稳定、区分大小写的引用键。
inbounds:定义本机怎样接收流量
inbounds 是入站数组,每一项代表一个监听入口。桌面端常见入口包括 SOCKS、HTTP 或由客户端管理的透明代理入口。最基础的 SOCKS 入站至少要明确 listen、port、protocol 与 settings。监听地址设为 127.0.0.1 时,仅允许本机程序访问;改成 0.0.0.0 会监听全部网络接口,局域网设备可能访问该端口,因此不能把两者当成等价写法。
{
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
]
}
逐字段读取入站配置
tag:把该入口命名为socks-in,后续规则可以通过inboundTag只处理来自这个入口的请求。listen:指定绑定地址。127.0.0.1是本机回环地址,适合只供当前电脑使用的客户端配置。port:指定监听端口。示例使用 10808,浏览器或应用的 SOCKS5 代理端口也必须同步填写 10808。protocol:声明应用如何与本地核心通信。这里是 SOCKS,不代表远端节点也使用 SOCKS。settings.udp:允许 SOCKS 入站接收 UDP 请求。它只打开入站能力,最终是否可用还取决于远端协议、传输方式和目标应用。sniffing:从 HTTP 请求或 TLS 握手中恢复目标域名,让基于域名的分流规则有机会命中。
端口冲突发生在核心创建监听套接字时。如果 10808 已被另一个进程占用,inbounds 尚未开始接收流量,后面的 routing 与 outbounds 也不会执行。在 v2rayN 中可以进入「设置」→「参数设置」,调整本地 SOCKS 端口;修改为 10818 后,还要把浏览器代理、系统代理或其他应用中的端口同步改为 10818。
outbounds:定义代理、直连与拦截出口
outbounds 是出口数组。每个出口都要有唯一 tag,protocol 决定核心如何处理离站流量。远端代理出口包含服务器地址、端口、用户标识和传输参数;直连出口使用 freedom;主动终止连接的出口使用 blackhole。三者可以同时存在,再由 routing 选择具体出口。
proxy:VMess 代理出口
- 协议
- VMess
- 服务器端口
- 443
- 传输
- WebSocket
- 传输安全
- TLS
节点参数通常由订阅导入,address、id、路径和传输安全必须与服务端一致。
direct:直接连接
- 协议
- freedom
- 远端节点
- 不需要
- 典型用途
- 局域网与指定域名
- 引用标签
- direct
直连表示由本机网络直接访问目标,不经过 proxy 出站。
block:终止连接
- 协议
- blackhole
- 远端连接
- 不建立
- 典型用途
- 广告域名规则
- 引用标签
- block
命中后由核心终止请求,适合明确需要拦截的目标集合。
默认出口
- 确定方式
- 数组第一项
- 示例标签
- proxy
- 生效条件
- 规则未命中
- 排查重点
- 排列顺序
希望未分类流量走代理时,应把 proxy 放在 outbounds 第一项。
{
"outbounds": [
{
"tag": "proxy",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "node.example.net",
"port": 443,
"users": [
{
"id": "11111111-1111-4111-8111-111111111111",
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"wsSettings": {
"path": "/connection"
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
]
}
上面的域名、用户标识与路径用于展示结构,不能替代订阅中的真实节点参数。VMess 的 settings 描述用户与服务器,streamSettings 描述传输层。即使地址和端口正确,只要 WebSocket 路径、TLS 设置或用户标识不一致,连接仍会失败。
结论:先确认默认出口,再检查复杂规则
临时停用 routing 后仍无法访问,问题更可能位于 proxy 出站参数或网络连接;停用 routing 后恢复正常,则应回到规则顺序、匹配条件和 outboundTag 引用继续检查。
routing:按条件把请求交给指定出口
routing 不负责创建监听,也不保存远端节点凭据。它的职责是读取请求特征并返回一个出站标签。rules 数组按照从上到下的顺序匹配,通常在第一条有效规则命中后停止继续查找。因此,应把范围小、优先级高的规则放在前面,把覆盖面大的兜底规则放在后面。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "block"
},
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"inboundTag": [
"socks-in"
],
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
三条规则分别解决什么问题
- 第一条读取 GeoSite 分类,匹配广告域名后交给
block。该规则依赖本地 GeoSite 数据能够被核心正常读取。 - 第二条匹配私有 IP 范围并交给
direct,用于避免局域网地址绕到远端代理出口。 - 第三条限定来源为
socks-in,并把剩余 TCP、UDP 请求交给proxy。它的范围较大,所以放在精确规则之后。
| 字段 | 检查对象 | 常见取值 | 容易出现的问题 |
|---|---|---|---|
domain |
目标域名 | domain:、full:、geosite: |
分类数据过旧,域名未归入预期集合 |
ip |
目标 IP | CIDR、geoip:private |
域名没有解析为 IP,导致规则未参与匹配 |
port |
目标端口 | 53、80,443、端口范围 |
误把本地监听端口当成目标端口 |
network |
传输类型 | tcp、udp、tcp,udp |
只写 tcp 后遗漏 UDP 请求 |
inboundTag |
流量来源 | socks-in |
引用名称与 inbounds 中的 tag 不一致 |
outboundTag |
目标出口 | proxy、direct、block |
引用了 outbounds 中不存在的标签 |
domainStrategy 控制域名与 IP 规则之间的解析策略。AsIs 优先按原始域名进行匹配,不会为了所有 IP 规则主动解析域名;IPIfNonMatch 会先尝试域名规则,未匹配时再解析 IP 并继续检查 IP 规则;IPOnDemand 会在匹配过程中更积极地触发解析。普通分流配置常从 IPIfNonMatch 开始,既保留域名分类能力,也让私有 IP 等规则有机会生效。
结论:规则顺序比规则数量更重要
先放广告拦截与局域网直连,再放覆盖全部 TCP、UDP 的代理规则。若宽泛规则提前出现,后续更精确的 direct 或 block 规则可能没有执行机会。
tag 怎样把三段配置串成完整链路
tag 的关键要求是“定义存在、拼写一致、用途明确”。假设入站标签是 socks-in,三个出站标签分别为 proxy、direct 与 block,那么 routing 只能引用这四个已经定义的名称。把 outboundTag 写成 Proxy 或 proxy-main 都不会自动关联到 proxy。
inbounds[0].tag = "socks-in"
routing.rules[2].inboundTag = ["socks-in"]
outbounds[0].tag = "proxy"
routing.rules[2].outboundTag = "proxy"
outbounds[1].tag = "direct"
routing.rules[1].outboundTag = "direct"
outbounds[2].tag = "block"
routing.rules[0].outboundTag = "block"
按请求实际经过的顺序检查
- 确认应用代理类型为 SOCKS5,地址是 127.0.0.1,端口与 inbounds.port 相同。示例端口为 10808。
- 确认核心日志中没有“地址已被占用”或配置解析失败信息。监听失败时不要继续检查远端协议。
- 确认请求来自预期入站。如果规则限制了
inboundTag,从另一个 HTTP 入站进入的请求不会命中该规则。 - 按 routing.rules 的排列顺序寻找第一条匹配项,记录其
outboundTag。 - 在 outbounds 中寻找完全同名的 tag,并检查对应 protocol、服务器地址、端口及 streamSettings。
- 若没有任何规则命中,检查 outbounds 第一项是否确实是计划使用的默认出口。
如果要按来源区分策略,可以设置多个入站。例如 10808 的 socks-in 默认走 proxy,10818 的另一个 SOCKS 入站默认走 direct。此时两个入口必须使用不同 port 和不同 tag,再分别编写带 inboundTag 的规则。只复制一份入站却保留相同端口,会在启动阶段直接产生监听冲突。
修改配置时的安全步骤与常见问题
v2rayN 会根据当前节点、路由设置与核心选项生成运行配置。直接编辑生成文件可能只在当前进程周期内有效,切换节点、更新订阅或重启客户端后,文件可能再次生成。需要长期保留的路由逻辑,应优先在客户端提供的路由设置中维护;需要调整本地端口时,使用「设置」→「参数设置」,并同步所有调用该端口的应用。
- 修改前保存当前可用配置副本,每次只调整一个字段组。
- 编辑 JSON 后先检查逗号、引号、数组和对象闭合关系,再启动核心。
- 调整 outbounds 顺序时,记录第一项的 tag,因为它关系到未命中规则时的默认出口。
- 调整 routing.rules 时,从精确规则到宽泛规则排列,并逐条记录预期出口。
- 更新订阅后重新检查协议、传输、TLS、服务器端口与用户标识是否完整导入。
- 路由分类结果异常时,检查 GeoIP 与 GeoSite 数据是否能被当前核心读取。
端口 10808 能连上,为什么网页还是打不开?
本地端口能连接只说明 inbounds 已监听。把日志级别临时设为 info,检查请求是否命中 proxy,以及 VMess 出站的服务器地址、443 端口、用户标识、WebSocket 路径和 TLS 设置是否与订阅一致。
写了 direct 规则,目标域名为什么仍走代理?
先检查该规则是否排在宽泛的 proxy 规则之前,再确认 domainStrategy 与匹配类型。若规则按 IP 分类,可将策略设为 IPIfNonMatch,并确认域名解析结果确实落入目标 IP 范围。
outboundTag 可以随便命名吗?
名称可以自定义,但必须与 outbounds 中某项的 tag 完全一致,并避免重复。建议使用 proxy、direct、block 这类职责清晰的短名称,修改名称时同步搜索全部 routing 引用。
订阅更新后手工路由为什么消失了?
运行配置可能由 v2rayN 重新生成。把长期规则写入客户端的路由设置,不要只改临时生成的 config.json;更新后再检查规则顺序与出站标签是否保持一致。
VMess 与 VLESS 的配置结构完全相同吗?
顶层仍使用 inbounds、outbounds 与 routing,但出站 protocol、settings 用户字段及 streamSettings 组合会不同。不要只替换 protocol 字符串,应以订阅导入的完整节点参数为准。
读懂 config.json 的重点不是记忆全部字段,而是保持固定排查路径:入站是否监听、请求带着什么目标信息、哪条规则先命中、outboundTag 指向哪个出口、该出口能否完成连接。沿着这条链逐段验证,比同时修改端口、协议和路由更容易定位根因。