本文适合已经完成客户端导入、希望读懂内核运行配置的用户。先用一份只含本地入站、直连和拒绝出站的完整 JSON 建立结构,再追踪 tag 引用、路由顺序与 DNS 的关系。示例不含远端代理服务器;读完可判断请求从哪里进入、由哪条规则处理,以及修改后应检查哪些字段。
一、先区分客户端设置与内核配置
v2rayN、v2rayNG、v2flyNG 是客户端,不等于内核本身。客户端负责管理订阅、节点和操作界面,再把相关设置转换为内核可读的配置。v2rayNG 使用 Xray 内核,v2flyNG 使用 v2fly 内核;v2rayN 的运行配置则需要结合当前选择的内核判断。不同内核、不同版本的字段支持范围不能直接画等号。
本文采用 V2Ray 传统 JSON 配置结构中的常见字段。阅读实际配置时,先确认它是内核配置,还是客户端自己的设置文件。界面里保存的订阅分组、窗口选项、更新偏好,不一定出现在内核的 config.json 中;反过来,运行配置中的本地端口也可能由客户端自动生成。
这条链描述的是显式使用本地代理的应用。仅启动内核,不会自动让所有程序接入本地端口。系统代理、应用内代理与 TUN 的接入方式不同;本篇先固定为 SOCKS 或 HTTP 入站,避免把接入范围问题误判为路由错误。
二、一份完整的 config.json 示例
下面是用于拆读结构的完整配置。它监听两个回环地址端口,把 example.org 的精确域名请求拒绝,其余流量直连。example.org 是文档示例域名,不代表可用节点。配置中没有 VMess 或 VLESS 远端出站,因此它不会把流量转交给代理服务器。
{
"log": {
"loglevel": "warning"
},
"dns": {
"servers": [
"1.1.1.1"
]
},
"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": "block",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": [
"full:example.org"
],
"outboundTag": "block"
},
{
"type": "field",
"ip": [
"127.0.0.0/8",
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16"
],
"outboundTag": "direct"
},
{
"type": "field",
"inboundTag": [
"socks-in",
"http-in"
],
"network": "tcp,udp",
"outboundTag": "direct"
}
]
}
}
标准 JSON 中,键名和字符串必须使用双引号,数组与对象最后一项后面不能多写逗号。代码块没有注释,可作为独立阅读样本保存;是否能由具体内核加载,仍应使用该内核的配置检查命令确认。
三、inbounds:监听地址、端口与入口标签
inbounds 是数组,因为同一个内核进程可以接收多个入口。每个入口的 protocol 决定接收什么协议,settings 的内部字段也随协议变化。本例 SOCKS 入口的 udp: true 表示允许 SOCKS UDP 转发能力,不表示所有应用的 UDP 都会自动被接管。
SOCKS 入口
- tag
- socks-in
- listen
- 127.0.0.1
- port
- 10808
- protocol
- socks
- auth
- noauth
应用需明确连接该 SOCKS 入口;回环监听把接入范围限制在本机。
HTTP 入口
- tag
- http-in
- listen
- 127.0.0.1
- port
- 10809
- protocol
- http
- settings
- 空对象
用于 HTTP 代理请求及 CONNECT 隧道,不等于在本地开放一个网站。
listen 与 port 共同确定监听位置。把 127.0.0.1 改为 0.0.0.0 会改变可接入范围,可能让其他设备访问该代理端口。本例又使用无认证 SOCKS,因此不应为方便连接就随意扩大监听范围;确有局域网需求时,应同时规划认证和防火墙。
tag 是配置内部引用的标识,不是服务器地址,也不会自动创建一个新端口。第三条路由规则中的 inboundTag 正是引用这里的两个字符串。把入口标签改名后,对应规则也必须同步修改,大小写和连字符都要一致。
四、outbounds:出站类型与默认去向
outbounds 定义连接离开内核时的处理方式。freedom 表示由本机直接连接目标,blackhole 用于拒绝流量。这里的 direct 与 block 只是人为命名的标签;真正决定出站行为的是 protocol,不是标签看起来像什么。
| 位置 | 字段或值 | 实际作用 |
|---|---|---|
| 第一项出站 | tag: direct | 供路由引用,并在本例中承担未匹配时的默认出站。 |
| 直连协议 | protocol: freedom | 直接建立到目标地址的连接。 |
| 第二项出站 | tag: block | 被精确域名拒绝规则引用。 |
| 拒绝协议 | protocol: blackhole | 不把请求转发到目标服务器。 |
在这里使用的常规路由机制中,没有规则匹配时会使用第一个出站。因此,调整 outbounds 数组顺序不是单纯整理显示顺序,而可能改变默认流向。本例又给两个已知入口写了末尾直连规则,让默认意图更容易被读出。
结论:改出站前先核对标签引用
先搜索所有 outboundTag,确认它们都能对应到现有出站的 tag;再检查第一项出站是否符合未匹配流量的预期。标签拼错不会自动退回到同名协议。
如果要接入远端节点,需要添加参数真实、协议受当前内核支持的代理出站,再把相应规则指向它。VMess 与 VLESS 的用户字段、传输层和安全设置不是同一套内容,不能只把 protocol 字符串改掉就认为转换完成。应以可信订阅导入后生成的配置为参照,逐项核对服务器、端口、用户标识与传输参数。
五、routing:规则顺序与匹配条件
routing.rules 是有顺序的规则数组。对一次请求,从前向后检查,遇到匹配规则便采用其指定的出站,不会继续把后面的规则全部执行一遍。把宽泛规则放在前面,可能让后面的精细规则一直没有机会命中。
- 先匹配精确域名。
full:example.org只匹配该完整域名,不包括它的子域名。只有请求携带或内核获得该域名时,这条域名规则才能参与对应匹配。 - 再匹配指定 IP 网段。本例列出回环与三个常见私有 IPv4 网段,匹配后走
direct。这不是完整的特殊地址清单,也没有覆盖 IPv6 私有或链路本地范围。 - 最后匹配两个本地入口。来自
socks-in或http-in,并且网络类型为 TCP 或 UDP 的请求,交给direct。
一条规则里,inboundTag 数组中的两个入口是“任意一个符合即可”;同一规则中不同条件字段则通常需要同时成立。第三条规则因此不是“来自这两个入口,或者是 TCP”,而是“来自这两个入口之一,并且网络类型符合”。
domainStrategy: "AsIs" 表示路由匹配不为 IP 规则主动把域名解析成 IP。若应用交给内核的是域名,第二条私有地址规则不会仅凭“这个域名最终可能解析为私有地址”就命中;若交来的是 IP,则可直接做网段匹配。该选项控制路由阶段的处理,不等于整个连接过程中不发生 DNS 查询。
六、dns 与 log:不要混淆解析和分流
dns.servers 在示例中配置了 1.1.1.1,它属于内核内置 DNS 的服务器设置,不会自动替换操作系统或浏览器自己的解析配置。仅写入这个字段,也不能保证所有解析请求都会通过代理。哪些模块调用内置 DNS、解析连接走哪条路径,要结合具体内核与相关策略判断。
- 路由策略看域名或 IP 如何参与匹配。本文的
AsIs不为 IP 路由规则额外解析域名。 - 出站连接仍可能需要解析。
freedom最终要建立连接,使用哪种解析路径还受出站策略和内核实现影响。 - 应用可能单独解析。应用内安全 DNS 或系统解析产生的请求,不会因为配置里存在
dns就必然被接管。 - 地址应按实际网络选择。示例解析器仅用于展示结构,不代表在每个网络环境中都可达或适合使用。
log.loglevel 设为 warning,适合先关注警告与错误。排查规则时可以短时改为 info;需要更细节时再考虑 debug。日志级别不是访问日志文件路径,也不保证所有版本都输出相同格式。分享日志前,处理订阅地址、用户标识、服务器地址和访问目标等敏感信息。
七、修改、验证与回退的操作顺序
客户端可能在切换节点、更新订阅或重新启动时重建运行配置。直接修改自动生成文件,下一次操作后内容可能被覆盖。先区分“查看生成结果”和“使用自定义配置”两种目的,再决定从客户端界面修改,还是使用其提供的自定义配置入口。
- 保存可回退副本。保留原配置,并记录当前内核类型、配置文件位置与监听端口,不要把订阅地址放进公开笔记。
- 每次只改一个逻辑点。例如只新增一条域名规则,先不同时更换 DNS、端口和远端节点,避免无法判断是哪项引起变化。
- 先做语法与配置检查。标准 JSON 检查能发现逗号和引号问题;内核检查才能进一步发现未知协议、字段类型及部分引用问题。
- 再启动并检查监听。如果提示地址占用,先确认 10808、10809 是否已有客户端使用,不要同时运行两份相同端口配置。
- 最后验证实际路径。先确认应用确实进入本地入口,再观察目标请求是否命中预期出站,失败时恢复上一份可用配置。
常见内核命令行检查写法如下,二者择一,不要连着对不同内核套用。可执行文件名称和调用方式需按本机系统调整;如果当前版本提示选项不识别,以它的 help 输出为准。检查通过只说明配置被接受,不证明远端服务器可达或分流符合预期。
v2ray test -c config.json
xray run -test -config config.json
桌面系统安装了 curl 时,可以使用下面的显式代理请求测试本例。第一条让 SOCKS 代理接收域名,适合检查 full:example.org 拒绝规则;第二条通过 HTTP 入口访问另一个文档示例域名,应走直连。两条命令均需在内核已正常启动、端口与本例一致的前提下执行。
curl --proxy socks5h://127.0.0.1:10808 --connect-timeout 10 https://example.org/
curl --proxy http://127.0.0.1:10809 --connect-timeout 10 https://example.com/
第一条预期连接失败,但单看失败提示无法区分拒绝规则、入口未启动或网络故障;第二条是否成功也取决于实际网络。应把命令结果与内核日志一起判断,不能仅凭网页未打开就认定某条规则已命中。
八、读配置时的常见疑问
导入订阅后,为什么不能把订阅内容直接存成 config.json?
订阅是客户端识别和更新节点的数据来源,不一定是内核可直接加载的完整配置。它可能包含分享链接或编码后的列表,也通常不负责定义本机监听入口。应先由客户端导入,再查看客户端生成的运行配置,不能只修改文件扩展名。
SOCKS 与 HTTP 两个端口可以交换吗?
端口数字本身没有绑定协议,配置里可以调整,但应用侧必须同步修改。把 HTTP 代理地址填成本文的 10808,不会因为端口能连接就自动变成 HTTP 入站。先核对 protocol,再核对端口与应用使用的代理类型。
为什么拒绝规则已经存在,请求却仍然直连?
按顺序检查四点:应用是否真的走代理入口;内核收到的是域名还是 IP;更早的规则是否已经匹配;当前运行的是否是刚修改的配置。还要注意,精确域名规则不会覆盖子域名。不要一开始就通过更换节点掩盖规则问题。
这份示例可以直接替换 v2rayNG 的运行配置吗?
不应直接替换。安卓客户端还需要结合 VPN 接入、DNS 和应用分流等设置生成运行内容,本文只演示本地 SOCKS、HTTP 与路由的基础结构。实际调整应使用客户端相应入口,并保留可恢复的配置;需要完整代理能力时,还必须提供有效的远端出站。