01 / CONFIG ROOT
JSON 结构总览与数据流
配置不是节点信息的简单集合
V2Ray 配置文件的根节点是一个 JSON 对象。常见顶层字段包括 log、dns、inbounds、outbounds、routing、policy 与 stats。其中,入站负责接收本机应用送来的连接,出站决定连接最终从哪里离开,路由负责把每条连接映射到某个出站,DNS 为域名匹配和目标解析提供结果,策略与统计则控制连接级行为。理解这条链路比背字段更重要:应用连接入站端口,内核识别目标域名或 IP,路由规则从上到下匹配,命中后选择出站标签,必要时 DNS 模块参与解析,最后由对应出站建立连接。
客户端生成的配置可能比手写示例复杂,因为图形客户端还会插入本地管理接口、统计入口、多个 DNS 服务器或兼容字段。排查时不要看到陌生字段就整段删除。先确认它属于哪个顶层模块,再观察是否被其他模块通过标签引用。例如路由规则中的 outboundTag 必须对应某个出站的 tag;策略中的级别编号需要与用户或入站使用的等级对应;DNS 的 tag 也可能被路由规则当作独立流量入口处理。
JSON 语法与类型约束
JSON 对标点和数据类型要求严格。对象使用花括号,数组使用方括号,字符串必须放在双引号中;对象成员之间需要逗号,但最后一个成员后不能保留尾逗号。布尔值写作 true 或 false,不能写成字符串。端口通常是数字,写成 "10808" 可能通过 JSON 语法检查,却不一定通过内核字段校验。注释也不是标准 JSON 的一部分,复制带有 // 或块注释的示例后,常会得到“invalid character”一类解析错误。
字段名称区分大小写。outboundTag 与 outboundtag 不是同一个字段,domainStrategy 也不能随意改写。另一个高发问题是层级放错:协议专属参数通常位于该对象的 settings 内,传输参数位于 streamSettings 内,不能把服务器地址直接放到出站根层。遇到“unknown field”时,应先检查字段所属层级,而不是先怀疑网络。
| 顶层字段 | 主要职责 | 常见引用关系 |
|---|---|---|
inbounds |
监听本地端口并接收 SOCKS、HTTP 等连接 | 通过入站 tag 被路由规则识别 |
outbounds |
定义代理、直连、阻断等出口 | 由 outboundTag 选择 |
routing |
按域名、IP、端口、协议和入站标签分流 | 读取入站标签并指向出站标签 |
dns |
提供域名解析和 DNS 服务器选择 | 受路由策略及域名匹配方式影响 |
policy |
设置超时、统计开关与系统级策略 | 可与用户等级、stats 配合 |
从最小配置开始扩展
手工维护配置时,应从能启动的最小集合开始:一个本地入站、一个可用出站、一个直连出站和少量路由规则。确认内核能够读取文件后,再加入 DNS、复杂规则和策略项。这样可以把“语法错误”“协议参数错误”和“路由逻辑错误”分开处理。一次粘贴数百行配置虽然省事,但任何括号错位都会让定位成本迅速上升。
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
}
]
}
图形客户端保存设置后可能重新生成配置,因此手改临时文件未必会永久保留。需要长期使用的规则,应优先写入客户端提供的自定义配置、路由规则或 DNS 设置入口。若只是分析启动失败,可导出或复制当前配置到独立位置,再逐段缩减测试,避免下一次订阅更新覆盖排错现场。
02 / INBOUNDS
inbounds 入站:监听、认证与流量识别
入站决定本机应用如何接入
inbounds 是数组,一份配置可以同时提供多个本地入口。桌面客户端常见 SOCKS 与 HTTP 两类入站:浏览器或支持代理设置的软件可以连接 HTTP 入口,支持 SOCKS5 的程序连接 SOCKS 入口。透明代理、隧道接口或局域网共享属于更复杂的接入形式,应在基础本地代理验证正常后再启用。每个入站最好设置清晰且唯一的 tag,例如 socks-in、http-in,方便路由规则按入口区分。
listen 决定监听地址。写成 127.0.0.1 时,通常只有当前设备可以连接,适合个人桌面环境;改为可被局域网访问的地址,会扩大可连接范围,此时需要同步考虑系统防火墙、入站认证和网络边界。不要为了排查“应用连不上本地端口”就直接扩大监听范围,先确认客户端是否启动、端口是否被占用,以及应用代理类型是否与入站协议一致。
port 是本地监听端口,必须与系统代理或应用内代理设置保持一致。端口数字本身没有固定要求,但同一地址上的两个程序不能同时占用同一个端口。若日志出现 address already in use,应关闭冲突进程、修改监听端口,或检查客户端是否重复启动。修改端口后还要更新浏览器、终端环境变量和其他应用中的代理地址,否则内核已正常启动,应用流量仍不会进入。
SOCKS 与 HTTP 入站参数
SOCKS 入站的 settings 常包含 auth 与 udp。本机回环地址上的个人使用场景常用 noauth;若监听范围扩大,应根据客户端能力配置访问控制。udp 决定该入站是否接收 UDP 请求,它不会自动保证远端协议、出站链路和目标服务都支持 UDP。HTTP 入站主要处理 HTTP 代理请求和 CONNECT 隧道,应用必须明确支持 HTTP 代理模式。把 SOCKS 端口填入 HTTP 代理栏,常表现为连接立即关闭或握手格式错误。
{
"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": "http-in",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
]
}
sniffing 的作用与边界
sniffing 用于从连接早期数据中识别目标域名,使原本只拿到目标 IP 的流量仍有机会按域名规则分流。destOverride 中常见 http 与 tls,分别对应可识别的 HTTP 主机信息和 TLS 握手中的服务器名称。它不是解密网页内容,也不能保证所有连接都能恢复域名;加密客户端问候变化、非标准协议或直接访问 IP 时,路由仍可能只能看到 IP。
开启流量识别后,如果发现某些应用的目标被改写或连接行为异常,可以先仅保留必要的覆盖类型,再对照日志判断。路由设计不应完全依赖识别结果:重要的本地网段、保留地址与已知 IP 范围仍应配置 IP 规则。相反,关闭识别后,大量域名规则可能无法命中,尤其是由系统先完成解析再提交目标 IP 的应用。是否启用应结合入站方式和应用行为决定,而不是机械套用同一设置。
多个入站的分工
多个入站不仅是为了兼容不同代理类型,也可以承载不同路由策略。例如一个 SOCKS 入站使用常规分流,另一个入站固定走指定出站。做法是在路由规则中使用 inboundTag 匹配入口,再设置目标 outboundTag。入口专用规则应放在通用域名规则之前,否则连接可能先被更宽泛的规则截获。
排查入站时可以分三步确认:先看内核日志是否显示监听成功,再检查本机是否存在对应监听端口,最后确认应用请求是否真正进入。若内核没有收到连接,问题通常位于应用代理设置、系统代理状态或端口冲突;若已收到连接但无法到达目标,再转向路由、出站和 DNS。不要在第一步尚未成立时反复修改服务器协议参数。
03 / OUTBOUNDS
outbounds 出站:协议、服务器与传输层
出站数组与标签设计
outbounds 描述连接离开内核的方式。常见配置至少包含一个代理出站、一个 freedom 直连出站和一个 blackhole 阻断出站。代理出站连接远端服务器;直连出站使用本机网络访问目标;阻断出站用于明确拒绝某类连接。路由模块只通过标签选择出口,因此标签应稳定、简短并表达用途,例如 proxy、direct、block。更换节点时可以修改 proxy 内部服务器参数,而无需重写全部路由规则。
数组顺序可能影响没有显式路由结果时使用的默认出口。为了避免依赖隐含行为,重要流量应通过规则明确指向标签,同时保持主要代理出站位于易于识别的位置。图形客户端可能根据当前节点动态调整第一项,手工合并配置时不要只凭数组位置判断出口用途,应同时检查 tag、protocol 和协议设置。
协议参数与传输参数分层
一个代理出站通常分成两部分:settings 保存协议本身需要的服务器、端口和用户信息;streamSettings 保存底层网络、TLS、REALITY 或 WebSocket 等传输设置。两部分必须与服务端一致。协议正确但传输层不一致时,常见表现是 TCP 已建立后握手失败;传输层正确但用户标识错误时,则可能由远端立即拒绝。
下面示例展示 VLESS 出站的结构位置,域名、标识和公钥均为说明结构的示例值,使用时必须替换为实际配置。security 位于用户对象内,描述 VLESS 用户层设置;security 也会出现在 streamSettings,后者表示传输安全方式。两个同名字段处于不同层级,不能互相替代。
{
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "00000000-0000-4000-8000-000000000000",
"encryption": "none",
"flow": "xtls-rprx-vision"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"serverName": "www.example.com",
"fingerprint": "chrome",
"publicKey": "replace-with-server-public-key",
"shortId": "0123456789abcdef"
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "none"
}
}
}
]
}
address、serverName 与目标域名不是一回事
address 是客户端实际连接的服务器地址,可以是域名或 IP。TLS 或 REALITY 相关的 serverName 则用于握手中的服务器名称,两者有时相同,有时由服务端配置决定。路由中的目标域名又是应用原本要访问的站点。排错时必须区分这三者:服务器地址解析失败属于连接入口问题;服务器名称不匹配通常表现为握手失败;应用目标域名走错出口则属于路由问题。
若服务器地址使用域名,内核在建立代理连接前也需要解析它。DNS 规则写得过于激进时,可能让服务器域名的解析本身被送入尚未建立的代理路径,形成循环依赖。稳妥做法是为服务器域名安排可用的初始解析路径,或按客户端提供的服务器地址处理方式配置。修改 DNS 后出现所有节点同时失效,应优先检查这一层,而不是逐个重填节点。
多代理出站与选择关系
一份配置可以包含多个代理出站,例如 proxy-main 与 proxy-alt。但 V2Ray 核心配置中的多个出站并不自动等于图形客户端里的延迟选择或故障转移。具体选择由路由规则、负载策略或客户端生成逻辑决定。不要仅把多个节点对象追加进数组就期待自动切换。v2rayN、v2rayNG 与 v2flyNG 的节点选择界面会生成对应配置,手工配置时则要明确每个标签由谁引用。
出站失败排查应从外向内进行:确认服务器地址可解析,确认目标端口可连接,再核对协议用户字段,最后检查传输安全与网络类型。日志中的 timeout 多指向地址、端口或路径不可达;handshake failed 更接近传输层参数;invalid user 或认证相关提示则应回到用户标识。详细的 TLS 错误分类可继续阅读TLS 证书报错排查清单。
04 / ROUTING
routing 路由规则:匹配顺序与分流写法
规则从上到下命中
routing.rules 是有顺序的规则数组。内核逐条检查连接属性,通常在匹配到适用规则后选择对应出站,因此规则顺序直接决定结果。范围更具体、优先级更高的规则应放在前面,兜底规则放在后面。例如阻断本地不需要的协议、处理内网地址、指定某些域名直连,然后再安排代理或默认出口。若先写一个范围很大的域名规则,后面的精确规则即使语法正确也可能没有机会生效。
规则中的多个匹配维度通常用于共同约束一条连接。例如同一规则同时包含 inboundTag 与 domain,表示连接既要来自指定入站,又要满足域名条件。一个维度内部的多个条目则通常表示该维度内任一项命中。设计复杂规则时,建议先把目标写成自然语言:“来自 socks-special 入站且目标属于 example.com 的连接走 proxy-alt”,再对应到字段,避免把“并且”和“或者”的关系写反。
domainStrategy 与域名匹配
domainStrategy 决定路由过程中何时为了 IP 规则解析域名。常见思路包括尽量按域名匹配,只有在必要时解析为 IP,或在域名规则未命中后再尝试 IP 规则。不同内核线和配置场景支持的取值需要以客户端当前内核行为为准,但原则一致:解析动作会引入 DNS 依赖,策略越积极,越要确认 DNS 路径稳定。
域名条目常见写法有完整匹配、子域范围、关键词与规则数据集。full:example.com 只匹配完整域名;domain:example.com 可覆盖该域及其子域;keyword:example 范围更宽,误匹配风险也更高;geosite: 条目引用内核可用的域名数据分类。规则数据需要与当前内核资源匹配,分类不存在或资源未加载时,不能把它当作网络故障处理。
IP、端口与协议规则
IP 规则可写单个地址、CIDR 网段或 geoip: 数据分类。内网地址通常应明确直连,例如回环、私有网络和链路本地范围。端口可写单个端口或范围,用于约束特定服务流量,但端口并不能可靠代表应用类型,同一个端口可能承载不同业务。协议识别依赖内核能够识别的连接特征,只适合处理明确目标,不应替代域名和 IP 规则。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"full:intranet.example.com",
"domain:local.example"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "block"
},
{
"type": "field",
"inboundTag": [
"socks-special"
],
"outboundTag": "proxy"
}
]
}
}
默认出口与规则末尾
并非所有配置都需要写一条覆盖全部目标的末尾规则。未命中规则时使用哪个出站,与内核默认行为和出站排列有关。为了让配置更容易审计,可以保持主出口位置稳定,并把需要例外处理的流量明确列出。如果团队或多设备共享规则,建议在文档中写清“默认走向”而不是依赖维护者记忆。客户端导入新节点后,检查出站排序是否改变也是必要步骤。
分流失效时先观察目标在路由阶段以域名还是 IP 出现。若规则写的是域名,但日志只有 IP,检查入站识别与 DNS 处理;若目标域名可见但未命中,检查匹配前缀和规则顺序;若日志显示命中正确标签但连接仍失败,应转向对应出站。把“没有命中”和“命中后出站失败”区分开,可以避免在规则表里无休止地添加重复条目。
客户端自定义规则的落点
v2rayN 的路由设置、v2rayNG 与 v2flyNG 的分流设置最终会转换为核心可读取的规则。不同客户端对规则集合、预设模式和自定义条目的合并顺序可能不同。修改前先导出当前配置或查看运行配置,确认自定义规则位于预设规则之前还是之后。若客户端提供“绕过局域网”“全局”“规则”之类模式,它们控制的是生成逻辑,不只是界面上的开关。
国内直连与境外代理这类常见方案涉及域名分类、IP 数据和规则顺序的共同作用,不能只复制一行规则。完整写法与排错路径可参考V2Ray 路由规则配置实战。迁移规则时还要确认目标客户端使用的内核线和资源文件是否支持相同分类名称。
05 / DNS
DNS 配置:服务器选择、域名规则与出口关系
V2Ray DNS 解决什么问题
DNS 模块为内核需要解析的域名提供结果,也可以根据域名类别选择不同服务器。它与系统 DNS 并非完全替代关系:应用可能先在系统层解析并只把 IP 交给代理,也可能把域名原样交给 SOCKS 或 HTTP 入站;服务器地址本身也可能需要系统或内核完成初始解析。因此,判断 DNS 问题前要先确定查询由谁发起、目标域名在哪一层被解析,以及解析结果是否参与路由。
最简单的 servers 数组可以包含 localhost 或 DNS 服务器地址。更细的对象写法可以指定服务器地址、适用域名和查询预期。服务器顺序不应被简单理解成“第一个失败就永远使用第二个”,实际行为还会受到域名匹配、查询类型与内核实现影响。配置多个服务器时,应明确每个服务器负责哪些域名,而不是堆叠大量地址期待自动得到更优结果。
按域名选择 DNS 服务器
为服务器对象设置 domains 后,匹配的域名可优先使用该服务器。域名表达方式与路由规则相似,可以使用完整域名、域范围和可用的数据分类。这里的规则负责“向谁查询”,路由规则负责“查询流量或最终连接从哪个出口离开”,二者是不同层次。只写 DNS 域名条件而没有处理对应出口,不代表查询一定走预想路径。
{
"dns": {
"hosts": {
"router.example": "192.168.1.1"
},
"servers": [
{
"address": "localhost",
"domains": [
"full:router.example",
"domain:local.example"
]
},
{
"address": "1.1.1.1",
"domains": [
"geosite:geolocation-!cn"
],
"skipFallback": true
},
"localhost"
],
"queryStrategy": "UseIP"
}
}
hosts 可为特定名称提供静态映射,适合固定的本地服务名称或测试环境。它不应被用来维护大规模、频繁变化的地址表。静态映射会绕过常规查询,一旦地址变化,旧值可能持续导致连接异常。排查某个域名解析结果与系统不同的时候,别忘了检查 hosts,包括客户端界面生成的自定义主机记录。
查询策略与地址族
queryStrategy 控制查询地址类型的倾向。实际可选值及细节取决于所用内核,但通常涉及同时使用 IPv4 与 IPv6、仅查询其中一种或按环境选择。不要因为某次 IPv6 路径不可用就永久删除所有相关能力;更合理的做法是先确认本机网络、远端出站和目标站点是否形成完整链路。如果系统具备地址但没有可用路由,解析成功后仍会连接超时,这属于网络路径问题,不是 DNS 没返回结果。
域名规则使用 IP 分类时,内核可能需要先解析目标,再拿结果与 IP 规则比较。此时查询策略会间接改变路由结果:同一域名返回不同地址族,可能命中不同网段规则。设计配置时应避免让路由结论过度依赖偶然的单次解析结果。对于必须稳定直连的内网名称,使用清晰的域名规则和内网网段规则双重约束更容易维护。
DNS 查询如何选择出站
DNS 服务器地址本身也是网络目标,可以通过专用标签或路由规则控制出口。若使用普通 IP 地址作为 DNS 服务器,可按目标 IP 与端口识别;若使用域名形式的加密 DNS,还要先解决该服务器域名的初始解析。常见循环是:解析代理服务器需要 DNS,DNS 被路由到代理出站,而代理出站又必须先解析服务器地址。处理方式是为启动链路保留一个不依赖代理的可用解析入口,或使用客户端支持的明确引导设置。
出现 DNS 查询成功但网页打不开时,应继续看最终连接,而不是停在解析结果。可能的情况包括路由把解析后的 IP 送到错误出站、远端不支持相应地址族、目标端口被阻断或应用没有使用内核 DNS。反过来,网页能打开也不代表所有 DNS 都按配置执行,应用自身的解析机制可能绕过了本地代理。需要严格观察时,应结合日志中的目标形式、入站协议与应用代理方式。
缓存、FakeDNS 与排错边界
部分客户端和内核场景会使用缓存或 FakeDNS,以便透明接入时保留域名映射。FakeDNS 返回的是内部映射地址,内核收到连接后再还原真实域名;如果该地址被其他应用、系统组件或不匹配的入站处理,就可能出现看似异常的目标 IP。启用前应确认当前接入方式确实需要,并保持相关地址范围不与本地网络冲突。
排查 DNS 最有效的方法是逐层替换:先用一个明确可用的普通服务器验证基础解析,再恢复域名分组,随后加入查询策略和专用路由。每次只改一个变量,并记录目标域名、返回地址和最终出站标签。更系统的设置入口说明可结合站内关于 V2Ray 使用流程的客户端章节查看。
06 / POLICY
policy 策略:连接超时、用户等级与统计开关
策略对象的两层结构
policy 用于集中设置连接生命周期和统计行为,常见结构包含 levels 与 system。levels 以用户等级为键,每个等级下定义握手、连接空闲和上下行关闭后的等待时间等参数;system 控制入站与出站统计是否启用。多数个人客户端不需要复杂等级,但理解该结构有助于解释为什么某些连接在空闲一段时间后被释放,或为什么统计模块没有产生数据。
等级编号不是速度优先级,也不会自动让某个用户获得更高带宽。它只是把用户或协议对象引用的 level 映射到一组策略。若配置中只有等级 0,所有使用默认等级的连接就采用这一组值。添加等级但没有任何用户引用,不会产生实际效果。迁移服务端风格配置到客户端时,常见问题是保留了复杂等级表,却删除了原本引用它的用户对象,留下难以理解的冗余。
连接生命周期参数
handshake 通常控制连接建立阶段允许等待的时间;connIdle 控制没有数据活动的连接可保持多久;uplinkOnly 与 downlinkOnly 用于一侧数据结束后继续等待另一侧的时间。具体单位和支持范围应以当前内核字段定义为准。过短的空闲时间可能让长连接、消息推送或下载控制连接频繁重建,过长则会让已经无效的连接占用资源更久。
超时不是越大越稳定。服务器地址不可达时,过大的握手等待会让故障反馈变慢;网络频繁切换时,旧连接长时间保留也不会自动恢复。调整策略前先从日志确认断开原因:如果远端主动关闭,延长本地空闲时间没有意义;如果应用自身定期重连,也不应把每次重连归因于内核策略。
{
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300,
"uplinkOnly": 2,
"downlinkOnly": 5,
"statsUserUplink": false,
"statsUserDownlink": false
}
},
"system": {
"statsInboundUplink": false,
"statsInboundDownlink": false,
"statsOutboundUplink": false,
"statsOutboundDownlink": false
}
}
}
统计开关不是统计结果
策略里的统计字段只是允许核心收集相应维度的数据,还需要 stats 顶层对象以及可读取统计的接口或客户端功能配合。单独把所有开关改为 true,界面不一定自动出现数据。反过来,客户端为了显示流量信息而生成统计配置时,也可能附带 API 入站或内部路由,不能只保留 policy 而删除配套对象。
统计会增加一定的状态维护工作,个人环境只应启用真正需要的维度。例如只关心出站总量,就不必同时启用每个用户的上下行统计。配置审计时应问清三个问题:需要观察什么维度、由哪个接口读取、数据由哪个客户端页面展示。如果无法回答,优先保持简单配置,避免为了“字段齐全”加入无实际用途的模块。
客户端生成策略的处理方式
v2rayN、v2rayNG 和 v2flyNG 可能根据流量统计、连接测试或本地管理功能写入策略字段。手工覆盖配置时,应先关闭相关客户端功能或使用其支持的自定义入口,否则下一次启动可能重新生成。特别是桌面端同时运行系统代理、连接测试和统计显示时,运行配置通常不等于订阅里的一条节点链接。
策略排错应避免与网络排错混在一起。内核启动失败并明确指向 policy 字段时,检查类型、等级键和当前内核是否支持该字段;连接能建立但过早断开时,再比较空闲时间与应用行为;统计为空时,则检查完整的数据采集链。把这三类情况分开,才能判断是配置结构问题、连接生命周期问题还是客户端显示问题。
何时应保持默认
普通浏览、命令行代理与日常订阅使用通常不需要手工调整 policy。默认值经过通用场景考虑,除非日志和复现步骤能证明某个连接确实受策略时间影响,否则不建议为了追求“更快”修改。策略参数控制的是等待与状态,并不会提升远端线路质量或服务器吞吐。
如果确实需要调整,应先记录当前值和复现条件,每次只改变一个参数,并观察同一应用、同一网络路径下的结果。调整后连接问题没有变化,就恢复默认,继续检查出站与系统网络。配置大全的目的不是让每个字段都被改动,而是让必要改动有明确依据。
07 / LOG & STATS
日志、统计与运行配置:建立可观察的排错现场
log 字段与日志级别
log 决定内核输出哪些运行信息。常见级别从详细调试信息到警告和错误逐步收敛。日常使用可选择 warning 一类较简洁级别,复现复杂问题时临时提高详细程度,问题确认后再恢复。长期保持最详细日志会产生大量重复信息,重要报错反而更难定位,也可能占用额外磁盘空间。
日志通常分为访问记录与错误记录。访问记录回答“哪条连接进入、目标是什么、选择了哪个出口”,错误记录回答“在哪个阶段失败以及失败原因”。只看最后一行容易误判,因为最外层错误可能只是“连接结束”,真正原因在前几行的 DNS、路由或握手信息中。排查时应保留从内核启动到故障出现的完整时间段,并记录触发操作。
{
"log": {
"access": "",
"error": "",
"loglevel": "warning"
},
"stats": {}
}
空路径的具体处理方式与内核及客户端启动参数有关,图形客户端通常接管日志输出并在界面中展示。不要假设手工填写某个文件路径后客户端一定读取该文件。Windows、macOS、Android 与 Linux 的应用数据目录和权限模型不同,优先使用客户端自带日志窗口或导出功能。需要重新安装客户端时,可从安装包页面按平台选择对应版本。
读取日志的阶段顺序
启动日志先检查配置解析。如果出现 JSON 字符位置、未知字段或类型错误,内核尚未进入网络连接阶段,此时修改节点地址没有意义。配置加载成功后检查入站监听,确认端口与地址;随后观察 DNS 和路由,确认目标被识别并命中预期出站;最后才看远端连接、TLS 或协议握手。沿着数据流阅读日志,可以把一长串信息归入明确阶段。
常见错误文本不应脱离上下文解释。timeout 可能发生在 DNS、TCP 连接或握手阶段;connection refused 可能来自本机端口、远端端口或中间转发;failed to find an available destination 可能与出站选择、解析结果或策略有关。判断依据是错误前后的模块名称、目标地址和标签,而不是只搜索一个英文短语。
运行配置与保存配置
客户端界面保存的是节点、订阅、路由模式和应用设置,真正交给内核的运行配置可能在启动时动态合成。排查时应查看运行配置,而不是只看订阅链接中的节点字段。客户端可能增加本地入站、API、统计、DNS、直连和阻断出站;系统代理设置也位于内核配置之外。运行配置正确但应用没有流量进入时,就应检查系统代理或应用代理,而不是继续改 JSON。
复制运行配置用于测试时,要注意其中的临时端口、客户端内部标签与路径。独立启动内核前,应把环境依赖替换为当前机器可用设置。反过来,把一份手写配置导回客户端也可能被客户端重新整理。长期维护应选择一种主来源:要么以客户端设置为主,通过受支持的自定义规则扩展;要么以完整手写配置为主,避免两个来源轮流覆盖。
stats 与客户端流量显示
stats 顶层对象用于启用统计模块,但实际指标还取决于 policy 中的开关。部分客户端会通过内部 API 读取入站、出站或用户维度数据,并在界面中显示。若删除 API 对象或内部路由,统计可能停止,但代理连接仍然正常。这种“核心可用、界面数据为空”的情况应与节点失效分开处理。
统计值适合观察流量方向与连接是否经过某个入口,不适合被当作线路质量评分。吞吐受目标服务器、网络路径、并发和应用行为共同影响。配置页不应为了看到更多数字就开启所有统计维度。先确定排错目标,例如验证某个入站是否收到上行流量,再启用对应维度,完成后恢复简化设置。
构造最小复现
可靠的排错记录至少包含:使用的客户端名称、操作系统平台、内核家族、触发步骤、错误发生阶段、相关标签和经过删减的配置结构。节点凭据与订阅内容不应公开复制。可以保留协议类型、字段层级和示例化地址,使他人仍能判断结构问题。
如果内核在读取配置后立即退出,进一步的日志定位方法可看通过日志定位 config.json 配置错误。如果错误集中在 certificate invalid、serverName 或握手阶段,则转到TLS 证书报错排查清单,按系统时间、服务器名称与证书链顺序检查。
08 / VALIDATION
完整配置组装、验证顺序与故障分支
组装一份可读的基础配置
完整配置应先保证标签关系清楚,再追求规则数量。下面的基础结构包含本地 SOCKS 入站、代理出站、直连与阻断出口、简单 DNS 和路由。代理服务器信息仍是示例,不能直接用于连接;示例重点是展示各模块如何闭环引用。实际使用时,图形客户端通常根据订阅自动填入代理出站,手工规则更适合通过客户端支持的配置入口合并。
{
"log": {
"loglevel": "warning"
},
"dns": {
"servers": [
"localhost"
]
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "00000000-0000-4000-8000-000000000000",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com"
}
}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:category-ads-all"],
"outboundTag": "block"
}
]
},
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300
}
}
}
}
第一层:语法和结构验证
配置无法启动时,先检查 JSON 是否完整。重点查看括号是否成对、数组成员间是否有逗号、字符串是否使用双引号、数字和布尔值是否写成正确类型。编辑器显示的报错行有时只是解析器最终无法继续的位置,真正缺失的逗号可能位于上一行。修复后再次读取配置,直到不再出现 JSON 解析错误。
语法通过后进入字段结构验证。检查字段名称、所属层级和内核支持情况。若配置来自另一条内核线、旧教程或不同客户端,某些字段可能不可用。Xray 与 V2Fly 有共同基础,也存在协议和功能差异,不能假设配置始终可以原样互换。需要了解两条内核线与客户端搭配,可读Xray 和 V2Fly 内核关系与选择建议。
第二层:标签与监听验证
全文列出所有入站和出站标签,再逐一检查引用。每个 outboundTag 都应能找到同名出站,每个 inboundTag 都应对应实际入口。标签大小写必须一致,重名标签则会让配置含义不清。随后确认每个入站监听成功,端口没有冲突,应用代理地址与协议类型完全一致。
如果应用无法访问,但内核没有任何对应连接日志,应把注意力放在系统代理和应用设置。桌面环境中,系统代理可能只影响遵循系统设置的程序;终端工具、游戏或独立浏览器配置可能有自己的代理入口。Android 客户端通常通过系统网络接口接管流量,排查重点则是应用权限、当前配置和连接状态。不同平台入口可在安装包页面查看。
第三层:DNS、路由与出站验证
确认连接进入后,记录日志中的目标形式。如果是域名,检查域名规则;如果已经是 IP,检查 IP 规则和入站识别。然后确认实际命中的出站标签。命中错误说明规则顺序、匹配范围或 DNS 解析结果需要调整;命中正确但失败,则检查该出站服务器解析、端口、协议与传输层。
可以临时减少路由规则来判断问题边界。先保留内网直连与一个明确代理出口,确认基础链路;再逐组恢复域名分类、阻断规则和专用入站规则。DNS 也按相同方法处理,从单一可用服务器开始,再恢复域名分组和专用出口。一次恢复一组,才能准确找到引入故障的变化。
常见故障分支
| 现象 | 优先检查 | 下一步 |
|---|---|---|
| 内核启动后立即退出 | JSON 语法、未知字段、端口占用 | 缩减到最小配置并逐段恢复 |
| 应用连接但无访问日志 | 应用代理类型、地址、端口、系统代理 | 确认请求是否进入正确入站 |
| 域名规则没有命中 | 目标是否已变成 IP、sniffing、规则顺序 | 同时观察域名和 IP 路由 |
| 所有节点在修改 DNS 后失效 | 服务器域名的初始解析与循环依赖 | 恢复基础 DNS,再逐项加入规则 |
| TLS 或 REALITY 握手失败 | 系统时间、serverName、传输参数 | 对照服务端配置检查字段层级 |
| 命中正确出站仍超时 | 服务器地址、端口、网络路径、地址族 | 区分解析超时、连接超时和握手超时 |
修改后的回归检查
配置恢复可用后,不要只验证一个网页。至少检查域名目标、直接 IP 目标、本地网络地址、需要直连的站点和需要代理的站点,确认规则边界符合预期;若启用 UDP,再用实际需要 UDP 的应用验证。随后重启客户端,确认配置能稳定重新生成并加载,避免只是临时运行文件有效。
订阅更新后还应检查自定义规则是否保留、当前节点是否仍映射到预期代理标签,以及客户端是否切换了内核。v2rayN 适合 Windows、macOS 与 Linux 桌面环境,v2rayNG 使用 Xray 内核,v2flyNG 是采用 V2Fly 内核的 Android 备选。三者界面不同,但排错主线一致:入口、识别、路由、解析、出口、握手逐层确认。
最后保留一份文字化变更记录,写明修改原因、涉及模块和验证结果。配置文件可以复制,网络环境和客户端生成逻辑却会变化;只有知道某条规则解决什么问题,后续才能判断它是否仍有必要。快速操作继续查使用文档,字段名称与协议概念查术语表,涉及具体错误时再进入对应博客文章,避免把所有知识堆进一份难以维护的配置。
继续查阅
完成结构理解后,可按实际任务进入安装包、快速上手、术语解释或日志排错文章。博客文章只讨论具体问题,本页保留配置结构的统一参考。