JSON 结构总览与读取顺序
先区分核心配置与客户端设置
V2Ray 配置文件是一个 JSON 对象。核心启动后读取顶层字段,再把入站监听、出站连接、路由选择、域名解析和连接策略组装为一条处理链。它不是按文件中字段出现的先后顺序逐行执行,因此把 routing 写在 inbounds 前面并不会改变运行结果。真正决定流量方向的是字段之间的引用关系,尤其是 tag、inboundTag、outboundTag 与 balancerTag。
v2rayN、v2rayNG 和 v2flyNG 都有自己的界面设置与数据存储。客户端显示的订阅分组、系统代理开关、分应用设置,不一定原样存在于核心 JSON 中。桌面端调试时,首先确认正在查看的是本次启动实际加载的配置,而不是旧备份或订阅原文。客户端重新生成配置后,直接写入运行文件的手工内容可能被替换。需要长期保留的规则,应优先填写到客户端提供的自定义路由、DNS 或高级配置入口。
常见顶层字段
| 字段 | 类型 | 作用 | 主要关联 |
|---|---|---|---|
log |
对象 | 定义访问日志、错误日志与日志级别 | 故障定位 |
inbounds |
数组 | 接收来自本机应用或网络接口的连接 | routing.inboundTag |
outbounds |
数组 | 定义流量最终使用的连接方式 | routing.outboundTag |
routing |
对象 | 按域名、地址、端口、协议和来源选择出站 | 入站与出站标签 |
dns |
对象 | 定义核心内部的域名解析行为 | routing.domainStrategy |
policy |
对象 | 定义连接超时、统计开关与系统级策略 | 用户 level、stats |
stats |
对象 | 启用核心统计模块 | policy 中的统计开关 |
最小配置并不等于只有一个服务器对象。完整处理至少需要一个入站和一个出站。入站决定应用怎样把请求交给核心,出站决定核心怎样处理请求。路由、DNS 和策略都可以暂时省略,此时核心使用默认行为;但一旦加入路由规则,所有被规则引用的标签必须真实存在。标签拼写区分大小写,proxy 与 Proxy 会被视为不同值。
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
}
]
}
这份示例只在本机回环地址监听 SOCKS,收到的流量全部交给 freedom 出站。它适合检查核心能否读取 JSON、端口能否监听,以及应用是否正确指向代理端口,但不包含远端代理服务器。listen 使用 127.0.0.1 时,局域网其他设备不能连接该端口;改为所有网络接口前,应先明确访问范围和系统防火墙规则。
JSON 语法边界
JSON 的对象键和字符串必须使用双引号,数组或对象最后一项后不能保留逗号,布尔值只能写 true 或 false,端口数字不能加引号。标准 JSON 不接受注释,因此说明文字应放在站外文档或客户端备注字段中,而不是插入运行配置。复制示例时还要留意全角标点、弯引号和不可见空格,这些字符常由富文本编辑器带入。
配置可读性主要依靠缩进、标签和分段。建议统一使用两个空格缩进,标签采用短小且能说明用途的英文词,例如 local-socks、proxy、direct、block。不要依赖数组位置表达用途。后续新增出站或调整路由时,稳定的标签能减少误指向。如果目标只是导入订阅并开始连接,不需要手写整份文件,可直接按V2Ray 使用教程操作;需要选择客户端时转到下载中心。
inbounds 入站:监听、协议与流量入口
入站对象负责什么
inbounds 是数组,每个元素代表一个独立入口。桌面客户端常见入口是本机 SOCKS 和 HTTP 代理端口;透明接管场景还可能使用 dokodemo-door。一个请求进入核心后会携带入站标签、目标地址、目标端口、网络类型等属性,这些属性随后交给路由模块匹配。入站不决定最终走代理、直连还是拦截,它只负责接收、解析并把请求送入处理链。
常用公共字段包括 tag、listen、port、protocol、settings、sniffing 与 streamSettings。其中 settings 的结构由协议决定:SOCKS 可设置认证方式与 UDP,HTTP 可设置账户,dokodemo-door 可设置转发目标。不同协议的字段不能混用,把 SOCKS 的 udp 放到 HTTP 入站中不会得到预期效果。
本机 SOCKS 与 HTTP 双入口
{
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
],
"routeOnly": true
}
},
{
"tag": "local-http",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
]
}
两个入站使用不同端口。支持 SOCKS 的应用连接 127.0.0.1:10808,只支持 HTTP 代理的应用连接 127.0.0.1:10809。同一个地址与端口不能被两个进程同时监听,如果客户端启动后提示端口占用,应先查系统中是否已有另一份客户端、旧核心进程或其他代理工具正在运行,再决定关闭进程还是修改端口。
auth: "noauth" 适用于仅绑定回环地址的本机入口。若监听范围扩展到局域网,访问控制就不应只依赖应用层认证,还要结合系统防火墙限制来源。配置中的 udp: true 表示 SOCKS 入站接受 UDP 转发请求,并不表示所有出站协议、传输方式和上游网络都一定能够完成 UDP 通信。出现网页正常而语音、游戏或域名解析异常时,需要从入站、路由、出站和上游支持四层分别检查。
sniffing 与目标还原
部分应用先把域名解析为地址,再向代理端口提交地址。此时路由模块看到的目标可能只有地址,域名规则无法直接匹配。sniffing 会从符合条件的连接中识别 HTTP 主机名或 TLS 握手里的服务器名称,以便路由模块获得域名线索。它不会把所有流量都变成可识别域名,也不应被理解为通用抓包功能。
destOverride 指定允许识别的类型。示例启用了 http 与 tls。routeOnly: true 表示识别结果主要用于路由判断,而不直接替换原始连接目标,这样可以降低目标改写带来的兼容差异。若某个应用在开启目标识别后连接异常,可先只对 SOCKS 入站启用,再按应用测试;不要在未定位原因时同时改动路由、DNS 和出站传输。
| 字段 | 推荐检查点 | 常见现象 |
|---|---|---|
listen |
本机使用时优先绑定回环地址 | 绑定错误导致应用无法连接或暴露范围扩大 |
port |
确认未被其他进程占用 | 核心启动失败,客户端显示连接未建立 |
protocol |
与应用实际支持的代理类型一致 | 把 HTTP 请求发到 SOCKS 端口后立即失败 |
udp |
同时检查出站与上游能力 | TCP 正常但 UDP 业务异常 |
tag |
与路由中的 inboundTag 完全一致 | 限定入站的规则始终不命中 |
多入口的边界
多入口适合区分应用来源。例如给浏览器使用一个入站,给开发工具使用另一个入站,再在路由规则中按 inboundTag 指向不同出站。这样比频繁改动全局规则更清楚。若两个入站实际需要相同策略,则没有必要为了形式完整而继续拆分。入口越多,端口冲突、系统代理指向错误和规则遗漏的概率越高。
Android 客户端通常通过系统提供的网络接口接收应用流量,界面里的分应用代理、绕过选项会参与生成运行配置。桌面 JSON 的本地监听方式不能直接照搬到移动端。v2rayNG 使用 Xray 内核,v2flyNG 使用 v2fly 内核,两者界面字段和核心可用能力可能不同。需要手工调整时,应先确认当前客户端、当前内核以及配置实际生成位置,再对照字段处理。
outbounds 出站:服务器、协议与传输层
出站对象的三层结构
outbounds 也是数组。每个出站通常由三层信息组成:公共层用 tag 和 protocol 标识用途;协议层在 settings 中填写服务器地址、端口和用户参数;传输层在 streamSettings 中填写 TCP、WebSocket、gRPC、TLS 等设置。排查时应按这三层分开核对,不要把“协议正确”直接等同于“整条连接正确”。
服务器提供的协议、地址、端口、用户标识、传输方式、安全层和服务器名称必须作为一组读取。只修改协议名,或只把 VMess 用户参数替换成 VLESS 用户参数,不能完成配置转换。订阅导入的主要价值正是把这些关联字段作为一个完整节点交给客户端。手工录入时,建议逐项对照服务端资料,不依赖旧节点的默认值。
VLESS over TCP with TLS 示例
{
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "11111111-1111-4111-8111-111111111111",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com",
"allowInsecure": false
}
}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
]
}
示例中的域名和用户标识只用于展示结构,实际连接必须使用服务端提供的信息。address 是连接目标,既可以是域名也可以是地址;port 是数字。VLESS 用户项中的 id 用于身份识别,encryption 通常按服务端要求填写。它与外层 TLS 是不同概念:前者属于协议用户参数,后者属于传输安全层,不能互相替代。
network: "tcp" 表示底层传输为 TCP。security: "tls" 启用 TLS,tlsSettings.serverName 用于指定握手使用的服务器名称,通常应与服务端证书和部署信息一致。allowInsecure: false 保持正常的证书验证行为。连接失败时不应先把它改成 true 掩盖问题,而应核对系统时间、服务器名称、地址解析、证书覆盖范围和中间网络。
VMess 对象的字段位置
{
"tag": "proxy-vmess",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "vmess.example.com",
"port": 443,
"users": [
{
"id": "22222222-2222-4222-8222-222222222222",
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "vmess.example.com"
},
"wsSettings": {
"path": "/connection"
}
}
}
VMess 与 VLESS 都可能使用 vnext,但 users 内部字段不同。VMess 示例使用 security,而 VLESS 示例使用 encryption。WebSocket 传输还需要 wsSettings,其中路径必须与服务端一致。若服务端要求特定请求头,也应放在对应的 WebSocket 设置中。TCP、WebSocket 与 gRPC 各有自己的配置对象,不要保留上一种传输留下的无关字段。
direct 与 block 是处理出口
freedom 出站让核心直接连接目标,通常标记为 direct;blackhole 用于终止匹配流量,通常标记为 block。这两类出站不是远端节点,却是路由配置的重要组成部分。路由规则只负责选择标签,没有同名出站时无法完成处理。建议显式写出代理、直连和拦截三个标签,使规则意图在文件中直接可见。
数组中的第一个出站具有特殊意义:当没有路由规则命中时,核心通常使用第一个出站作为默认出口。因此出站顺序不能只按名称排序。若希望未命中流量默认走代理,就把代理出站放在前面;若希望默认直连,就把 direct 放在前面。更稳妥的做法是同时写清关键兜底规则,并在修改顺序后重新检查实际路径。
| 层级 | 代表字段 | 核对来源 |
|---|---|---|
| 公共层 | tag、protocol |
本地命名与协议类型 |
| 协议层 | address、port、users |
服务端或订阅信息 |
| 传输层 | network、security |
服务端传输设置 |
| 传输细节 | tlsSettings、wsSettings |
服务器名称、路径等部署信息 |
routing 路由:匹配条件、规则顺序与出口选择
路由规则按顺序处理
routing 根据连接属性选择出站。rules 是有序数组,核心从前向后检查,遇到第一条符合条件的规则后使用该规则指定的出口,后续规则不再参与该连接的选择。因此具体规则应放在前面,宽泛规则放在后面。把“全部端口”或“大范围地址”规则写在顶部,常会遮住下面更精确的域名规则。
一条规则内部的多个条件通常需要同时成立。例如同一规则同时写入 inboundTag、domain 和 port,表示来源入口、域名和端口都符合时才命中,而不是满足其中任意一个即可。需要表达“域名条件或地址条件”时,通常拆成两条指向同一出站的规则,结构更明确,也更容易从日志判断命中路径。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"inboundTag": [
"local-socks"
],
"domain": [
"full:internal.example.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"protocol": [
"bittorrent"
],
"outboundTag": "block"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
第一条只处理从 local-socks 进入且目标为指定完整域名的请求。第二条让私有地址范围直连,避免本地设备流量被送往远端。第三条按可识别协议进行处理。最后一条覆盖剩余 TCP 与 UDP 流量,作为显式兜底。所有 outboundTag 都必须在 outbounds 中存在;若标签改名,路由引用也要同步更新。
domainStrategy 决定何时解析
domainStrategy 影响路由模块面对域名目标时是否进一步解析地址。AsIs 主要按原始域名进行匹配,不为了地址规则主动解析;IPIfNonMatch 会先尝试域名规则,在域名规则未命中时解析地址,再测试地址规则;IPOnDemand 在规则判断需要地址时更早触发解析。策略越积极,地址规则越容易参与,但 DNS 行为也会更直接地影响路由结果。
如果配置主要依赖域名分类,且不需要按目标地址判断,可从 AsIs 开始。如果同时使用 geoip 或自定义网段,IPIfNonMatch 通常更容易理解:先看域名,未匹配再解析。调整该字段后出现路径变化,应同时检查 DNS 服务器选择、解析返回和缓存,而不是只检查路由数组。
域名匹配形式
| 形式 | 含义 | 适用情况 |
|---|---|---|
full:example.com |
只匹配完整域名 | 单一固定主机 |
domain:example.com |
匹配该域名及其常见子域范围 | 按站点域组织规则 |
regexp:^.+\.example\.com$ |
使用正则表达式匹配 | 结构复杂且前两种形式不能表达时 |
geosite:category-ads-all |
引用核心可用的域名分类数据 | 客户端与核心已准备对应数据时 |
正则表达式灵活但维护成本高。点号等字符需要按正则规则转义,放入 JSON 字符串后反斜线还要符合 JSON 转义要求。能用 full: 或 domain: 表达时,优先选择更直观的形式。分类数据规则则依赖客户端随核心提供的数据文件;若同一条规则在不同设备上表现不同,应检查数据文件来源与更新时间,而不是假设分类内容完全一致。
地址、端口、来源和网络类型
ip 可填写单个地址、CIDR 网段或核心支持的地址分类。port 可填写单个端口、范围或逗号分隔组合,例如 53、80-443。source 与 sourcePort 用于按来源信息限制规则,network 可区分 TCP 与 UDP,inboundTag 用于按入口区分应用路径。这些条件应围绕实际需求组合,不要为了字段齐全而全部写入。
按端口判断只能说明目标端口,不能可靠代表应用或协议。网页服务可以使用非标准端口,其他服务也可能使用常见端口。需要稳定识别目标时,优先结合域名、地址和入站来源。按协议识别则依赖核心能否识别对应流量,无法识别时规则不会命中。路由设计应保留清晰兜底,避免未识别连接落入意外出口。
复杂分流建议从三条规则起步:私有地址直连、明确需要处理的目标走指定出口、剩余流量使用默认出口。确认基础路径稳定后,再逐批加入域名分类、端口和来源条件。一次导入大量规则会让冲突位置难以确认。需要理解常见分流术语,可配合术语手册查阅;遇到规则已命中但连接仍失败,则继续检查出站和 DNS,而不是反复调整匹配顺序。
dns 配置:解析服务器、域名分组与路由联动
核心 DNS 与系统 DNS 的边界
dns 定义核心内部发起域名解析时使用的服务器和匹配方式。它不等同于操作系统的全部 DNS 设置。应用可能先在系统层完成解析,再把地址交给代理;应用也可能通过代理提交域名,由核心或远端处理。判断某条 DNS 规则是否参与请求,必须先确认域名在哪一层被解析,以及入站目标识别是否提供了域名信息。
路由中的 domainStrategy 可能触发核心解析,出站连接服务器地址也需要解析,部分 DNS 查询还可能作为普通流量再次经过路由。配置错误时容易出现循环依赖:核心为了连接代理服务器需要解析其域名,解析请求又被路由到尚未建立的代理出站。解决方向是让启动链上的必要目标拥有明确、可达的解析路径,并保持规则简单。
{
"dns": {
"hosts": {
"router.example": "192.168.1.1"
},
"servers": [
{
"address": "223.5.5.5",
"domains": [
"domain:example.cn"
],
"expectIPs": [
"geoip:cn"
]
},
{
"address": "1.1.1.1",
"domains": [
"domain:example.com"
]
},
"localhost"
],
"queryStrategy": "UseIP"
}
}
hosts 提供静态映射,适合固定的本地服务名或明确需要覆盖的少量域名。它不是大型域名列表的替代方案。静态映射变更后不会自动跟随真实服务变化,因此只应配置可维护的目标。示例把 router.example 指向私有地址,用于说明结构;实际配置应按本地网络信息填写。
servers 按顺序列出解析服务器。对象形式可附加 domains,让特定域名优先交给该服务器;字符串形式可作为通用服务器或回退项。localhost 表示使用本机解析能力。若客户端已经管理 DNS,核心配置还可能经过客户端改写,最终行为应以运行时配置和日志为准。
domains 与 expectIPs
domains 决定哪些域名优先使用当前服务器,它采用与路由域名规则相近的写法。精确主机可使用 full:,整个域范围可使用 domain:,分类数据可使用对应分类标识。服务器对象没有 domains 时,通常作为通用候选。多个服务器都符合时,执行细节还会受到核心实现和查询策略影响,因此应减少重叠范围。
expectIPs 是对解析结果的预期筛选。示例要求第一组服务器返回的地址符合指定地址分类;若结果不满足,核心可继续考虑其他候选。它适合表达“该域名组应解析到某类地址”的约束,但不能修复上游本身不可达、服务器响应超时或分类数据缺失。排错时先暂时移除该限制,确认基础查询是否成功,再恢复结果约束。
queryStrategy 与地址族
| 策略 | 主要行为 | 使用前检查 |
|---|---|---|
UseIP |
允许查询可用地址类型 | 系统与出站是否都能处理返回地址 |
UseIPv4 |
优先限定为 IPv4 查询结果 | 目标是否提供 IPv4 地址 |
UseIPv6 |
优先限定为 IPv6 查询结果 | 本地网络和出站是否具备 IPv6 连通性 |
地址族选择必须与实际网络能力一致。解析得到 IPv6 地址不代表当前设备、路由器、代理服务器和出站链都能到达该地址。若出现部分域名长时间等待、换网络后恢复,可先检查返回地址类型与出站连通性。反过来,强制 IPv4 也可能使只提供 IPv6 地址的目标无法解析。策略应基于网络事实,而不是作为通用加速开关。
DNS 请求怎样经过路由
当 DNS 服务器填写地址时,查询目标可以直接进入出站选择;填写域名时,还需要先解决 DNS 服务器自身域名的解析。若希望某组查询经过代理,应为 DNS 目标编写可识别且不会形成循环的路由规则。最简单的检查方法是画出两条路径:业务域名由谁解析,DNS 服务器自身由谁解析。任一路径回到尚未建立的自身连接,都需要重新设计。
域名规则未生效时,先检查应用交给核心的是域名还是地址。若只有地址,可检查 SOCKS 请求方式、目标识别和路由的 domainStrategy。DNS 返回正确但连接目标错误时,再检查缓存、静态映射和客户端生成的附加规则。不要同时更换解析服务器、修改地址族并重排路由,否则恢复后也无法确定真正原因。
需要进一步理解国内外域名分组、远端解析与地址规则的组合,可阅读博客中的V2Ray DNS 配置详解。文章侧重方案设计,本章侧重字段与执行边界。遇到客户端界面选项与手写字段不一致时,以客户端当前内核支持和实际生成配置为依据。
policy 策略:超时、用户等级与统计开关
policy 不负责选择出站
policy 用于定义连接生命周期和统计开关,不负责按域名或地址分流。常见结构包括 levels 与 system。levels 以用户等级为键,为使用同一等级的用户设置握手、空闲、上下行保持时间和统计项;system 控制入站与出站的系统级统计。若目标是改变某个域名的出口,应修改 routing,而不是在策略中寻找规则字段。
等级不是速度档位,也不是优先级排序。协议用户对象可通过 level 引用同名策略组,未显式设置时通常使用默认等级。配置多个等级只有在确实需要不同连接生命周期时才有意义。普通客户端配置通常保留一个等级即可,减少用户对象与策略对象之间的引用复杂度。
{
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300,
"uplinkOnly": 2,
"downlinkOnly": 5,
"statsUserUplink": false,
"statsUserDownlink": false
}
},
"system": {
"statsInboundUplink": false,
"statsInboundDownlink": false,
"statsOutboundUplink": false,
"statsOutboundDownlink": false
}
}
}
handshake 控制连接建立阶段允许等待的时间。数值过小会让高延迟网络或较慢握手过早失败,数值过大则会让真正不可达的连接等待更久。它不是网页加载总超时,也不决定应用自身的请求期限。遇到握手失败时,先检查地址、端口、传输层和网络可达性,再判断是否需要调整该值。
connIdle 表示连接在没有数据活动时可保持的时间。设得太短可能影响长连接、消息推送或间歇传输;设得过长会让不再使用的连接更久地占用资源。合理值取决于业务类型,不存在适用于所有网络的统一数字。移动网络频繁切换时,旧连接即使仍在核心中保留,也可能已经无法继续使用,因此还要结合客户端重连行为判断。
uplinkOnly 与 downlinkOnly 用于半关闭状态下的连接保留时间。当一侧数据方向结束后,另一侧可能仍需要短暂传输。过早结束会截断尾部数据,保留过久则延迟资源释放。普通使用中不建议先调整这两个字段;只有日志和业务表现明确指向半关闭处理时,再做单项测试。
统计需要两层同时启用
statsUserUplink 与 statsUserDownlink 控制用户级统计,system 下的字段控制入站和出站统计。要让统计数据真正产生,通常还需要顶层存在 stats 对象,并由客户端或 API 读取。只打开策略开关不会自动生成可见图表,也不会自动把结果写入某个页面。
{
"stats": {},
"policy": {
"system": {
"statsInboundUplink": true,
"statsInboundDownlink": true,
"statsOutboundUplink": true,
"statsOutboundDownlink": true
}
}
}
统计会增加一定处理与内存开销。只为排错临时观察入站和出站流量时,可以按需启用,完成后恢复必要范围。用户级统计还依赖协议用户具有对应等级和标识,适用于服务端管理或明确的数据采集场景。普通本地客户端更常关注出站是否有流量,而不是为每个用户建立统计层。
| 字段 | 单位或类型 | 调整风险 |
|---|---|---|
handshake |
秒 | 过短导致连接建立阶段提前终止 |
connIdle |
秒 | 过短影响长连接,过长延迟资源释放 |
uplinkOnly |
秒 | 影响上行结束后的连接保留 |
downlinkOnly |
秒 | 影响下行结束后的连接保留 |
statsInboundUplink |
布尔值 | 启用后产生对应统计数据与额外开销 |
策略修改的测试方式
调整连接策略时,应固定节点、路由和 DNS,只改变一个策略值。测试对象也要明确:握手问题用新建连接观察,空闲问题需要建立连接后等待,半关闭问题需要能够复现单向结束的业务。只刷新一次网页无法验证所有字段。测试完成后记录原值、修改值和现象,避免多轮调整后失去基准。
客户端可能在启动时生成默认 policy,也可能完全省略并使用核心默认值。省略字段不表示数值为零。若当前连接稳定,没有统计或生命周期方面的明确需求,保持默认行为通常比复制一组来源不明的参数更合适。需要比较 v2rayN、v2rayNG 与 v2flyNG 的平台定位,可转到横向评测;策略字段是否可用仍以各自内核和客户端实现为准。
完整组合、载入检查与分层排错
把各段组合为可追踪处理链
完整配置的重点不是字段数量,而是每条连接都能沿明确路径移动:应用连接入站,入站生成目标信息,DNS 在需要时提供解析结果,路由选择出站,出站按协议和传输设置建立连接,policy 管理生命周期。任何一层出现错误,都可能在客户端表现为“无法连接”。排错时必须把笼统现象拆成具体阶段。
{
"log": {
"loglevel": "warning"
},
"dns": {
"servers": [
"localhost"
],
"queryStrategy": "UseIP"
},
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
},
"inbounds": [
{
"tag": "local-socks",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "11111111-1111-4111-8111-111111111111",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com",
"allowInsecure": false
}
}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300
}
}
}
}
该示例展示结构关系,服务器信息仍需替换为实际资料。私有地址先匹配 direct,其余 TCP 与 UDP 流量交给 proxy。SOCKS 入站只绑定本机,DNS 使用系统解析能力,策略仅设置基础连接生命周期。配置中虽然定义了 block,但当前没有路由规则引用它;保留该出口便于后续增加明确的拦截规则。
第一层:文件能否被读取
先检查文件编码、JSON 语法、键名拼写和数据类型。常见错误包括漏写逗号、最后一项多出逗号、使用单引号、端口写成字符串、数组外少一层方括号,以及复制后出现全角标点。核心若在启动阶段直接退出,应优先查看错误日志中的字段路径和行列位置。不要在语法尚未通过时讨论路由是否命中。
图形客户端用户还要确认文件是否真的被当前进程加载。v2rayN 可能根据当前服务器、路由和 DNS 设置重新生成核心配置;v2rayNG 与 v2flyNG 也会根据移动端界面状态生成运行参数。修改一个未被使用的导出文件,不会改变当前连接。可通过客户端日志、配置预览或启动参数确认实际加载路径。
第二层:入站是否建立
核心启动后,检查本地监听地址和端口是否存在。应用代理类型必须与入站协议一致:SOCKS 应指向 SOCKS 端口,HTTP 应指向 HTTP 端口。若系统代理已开启但浏览器仍直连,检查系统代理指向、浏览器独立代理设置以及当前客户端模式。若应用立即提示代理服务器拒绝连接,通常先查核心是否运行、端口是否一致和本机防火墙。
仅某个应用异常时,不要立即判断节点失效。该应用可能不读取系统代理,也可能自带 DNS、HTTP/3 或独立网络设置。先用一个明确支持 SOCKS 或 HTTP 代理的测试应用验证入站,再回到目标应用检查代理能力。移动端则检查分应用范围和系统网络接口是否已建立。
第三层:路由与 DNS 是否给出预期目标
入站收到连接后,查看目标是域名还是地址,再检查路由第一条命中规则。如果日志显示走了错误出站,重点核对规则顺序、标签拼写和条件组合。若域名规则没有命中但地址规则生效,检查应用解析位置、sniffing 与 domainStrategy。若解析超时,暂时减少 DNS 服务器和结果限制,确认基础查询路径。
路由问题与 DNS 问题常互相影响。应分别提出两个问题:目标域名解析成了什么,解析完成后哪条规则匹配。只有把这两步分开,才能判断是解析结果不符合预期,还是规则顺序错误。直接反复更换节点无法解决本地规则冲突。
第四层:出站能否完成连接
出站阶段按固定顺序核对:服务器地址解析、端口可达、协议类型、用户参数、传输类型、安全层、服务器名称、路径或服务名。日志中的超时通常指向网络可达性或路径问题,立即断开常见于端口、协议或握手参数不一致。系统时间明显错误也会影响 TLS 连接。每次只修改一个字段,并保留能够恢复的原配置。
| 现象 | 优先检查 | 下一步 |
|---|---|---|
| 核心启动后立即退出 | JSON 语法、字段类型、端口占用 | 读取错误日志中的字段路径 |
| 应用无法连接本地代理 | 入站地址、端口、协议类型 | 确认应用代理设置与核心进程 |
| 部分域名走错出口 | 规则顺序、目标类型、DNS 结果 | 记录第一条命中规则 |
| 所有远端连接超时 | 服务器解析、端口、网络路径 | 再核对传输和安全层 |
| TCP 正常但 UDP 异常 | 入站 UDP、路由网络类型、出站能力 | 检查上游与应用行为 |
| 修改后重新启动仍未变化 | 实际加载文件、客户端自动生成 | 从运行配置反查设置来源 |
日志级别与最小复现
日常使用可保持较简洁的日志级别。定位问题时临时提高日志信息量,复现一次明确操作,然后恢复原设置。日志越多不代表结论越快;应围绕时间点、入站标签、目标、路由结果和出站错误读取。分享日志前要处理服务器地址、用户标识、订阅内容和本地路径等敏感信息。
最小复现配置只保留一个入站、一个代理出站、一个直连出站和最少规则。若最小配置能连接,再逐段加入 DNS 分组、额外入站、复杂路由与策略;在哪一步重新出现问题,范围就落在该段新增内容。若最小配置也失败,重点回到服务器参数、网络路径和内核兼容性。此方法比在完整配置中随机删字段更稳定。
仍无法判断时,可在FAQ 故障排查中按现象继续查找。需要重新安装客户端或确认平台对应关系,前往下载中心选择 v2rayN、v2rayNG 或 v2flyNG。桌面平台首选 v2rayN;Android 可按所需内核选择 v2rayNG 或 v2flyNG。重新安装前先记录当前订阅、路由与 DNS 设置,避免把配置问题和程序问题混在同一次操作中。