01 / JSON STRUCTURE
配置文件结构总览
先按流量方向理解顶层对象
V2Ray 与 Xray 的配置文件通常是一个 JSON 对象。真正需要先记住的不是字段数量,而是流量方向:应用程序先连接本机的入站监听,内核读取路由规则,选择一个出站,再通过目标出站建立连接。DNS 负责把域名解析成地址,policy 负责会话超时、统计等运行策略,log 则决定日志写到哪里以及记录到什么级别。
inbounds 和 outbounds 都是数组,因为同一实例可以同时监听多个本地端口,也可以准备多个出口。数组中的每个对象通常用 tag 命名,路由规则再通过标签引用它。标签只是实例内部的标识,不会发送给远端;名称可以自行确定,但应保持简短、稳定并能看出用途,例如 socks-in、proxy、direct 和 block。
一个便于阅读的配置顺序是:先写日志,再写 DNS,然后写入站、出站、路由和策略。JSON 本身不要求这个顺序,但固定排列能减少排查时间。遇到启动失败时,可以从文件开头向下检查;比较两份配置时,也更容易找到变化。图形客户端生成的顺序可能不同,只要层级和字段有效,执行结果不会因为对象键的排列顺序而改变。
{
"log": {
"loglevel": "warning"
},
"dns": {},
"inbounds": [],
"outbounds": [],
"routing": {},
"policy": {}
}
JSON 语法与配置语义是两层检查
配置能被 JSON 解析,只表示括号、引号、逗号和数据类型符合语法,并不代表所有字段都被当前内核接受。例如端口写成字符串,可能是合法 JSON,却不符合该字段需要整数的要求;出站标签拼写不一致,也可能等到匹配路由时才暴露问题。排查时要分两步:先确认 JSON 可以解析,再查看内核日志中关于未知字段、类型错误、标签缺失或协议设置不完整的提示。
标准 JSON 不允许注释,也不允许对象或数组最后一项后面保留多余逗号。复制示例时尤其要注意这一点。文档为了讲解经常展示片段,片段本身只有放进正确的父级对象才有效。例如单独复制一个 routing 对象时,必须把它作为顶层的 "routing" 值,而不是直接粘贴到文件末尾。字符串必须使用双引号,布尔值使用 true 或 false,不能加引号。
| 字段 | 数据形态 | 主要作用 | 常见检查点 |
|---|---|---|---|
log |
对象 | 控制访问日志、错误日志与记录级别 | 路径权限、日志级别是否过低 |
inbounds |
数组 | 接收来自浏览器、系统或局域网设备的连接 | 监听地址、端口占用、协议类型 |
outbounds |
数组 | 定义代理、直连和阻断等出口 | 服务器参数、标签、传输设置 |
routing |
对象 | 根据域名、IP、端口或入站标签选择出口 | 规则顺序、标签引用、解析策略 |
dns |
对象 | 定义解析服务器、静态映射和查询条件 | 查询路径、域名匹配、回退行为 |
policy |
对象 | 控制会话超时、流量统计等运行策略 | 策略层级、统计开关与统计模块配合 |
修改前建立可回退的基线
开始调整前,先让当前配置在不修改的情况下成功启动一次,并记下正在使用的本地端口、系统代理模式和内核名称。接着复制配置文件,给副本加上用途明确的文件名。每次只改一个逻辑单元,例如先增加直连出站,验证后再添加路由规则。一次改动多个区域虽然更快,但启动失败时很难判断是语法、标签还是协议参数造成的。
图形客户端可能在更新订阅、切换节点或重启核心时重新生成运行配置。此时直接编辑临时文件,改动可能不会长期保留。v2rayN 中应优先使用客户端提供的自定义配置、路由设置或高级选项;Android 客户端则先确认当前配置来自订阅节点还是手工配置。想了解某个术语的边界,可同时查看术语表,避免把“入站”“系统代理”和“路由模式”理解成同一个功能。
02 / INBOUNDS
inbounds 入站配置
监听地址决定谁能连接
入站是本机应用把流量交给内核的入口。最常见的本地入口是 SOCKS 和 HTTP 代理。listen 决定监听在哪个网络地址,port 决定端口,protocol 决定应用应使用哪种代理协议。只供当前设备使用时,监听地址建议写 127.0.0.1。这个地址只接受本机连接,浏览器、系统代理和同一设备上的其他程序可以使用,局域网中的其他设备无法直接接入。
如果需要把桌面客户端提供给同一局域网中的手机、电视或另一台电脑使用,入站通常会监听 0.0.0.0 或具体的局域网地址。这样做还需要同时处理系统防火墙、网络类型和访问控制,不能只改监听地址。共享设备填写的是运行内核那台电脑的局域网地址与入站端口,而不是 127.0.0.1。相关操作可参考v2rayN 允许局域网连接设置教程。
{
"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": {}
}
]
}
SOCKS、HTTP 与透明接管的边界
SOCKS 入站适合明确支持 SOCKS 代理的应用,能够承载 TCP,并可在设置允许时处理 UDP。HTTP 入站主要供使用 HTTP CONNECT 或普通 HTTP 代理的程序连接。两者都要求应用或系统代理明确指向对应端口。一个程序设置为 HTTP 代理时,不能把地址指向 SOCKS 端口;端口写对但协议类型选错,常见表现是连接立即断开、浏览器提示代理响应异常,或者日志里出现无法识别的握手数据。
TUN 模式与普通本地代理不同。它通过虚拟网络接口接收更广范围的系统流量,客户端还需要配置路由表、DNS 接管和权限。不要把 TUN 相关配置简单理解成多加一个 SOCKS 入站。v2rayN 会根据界面中的 TUN 选项组织运行参数,通常应先通过客户端界面启用,再检查日志,而不是把其他环境中的完整 TUN 片段直接拼进当前配置。普通系统代理已经满足浏览器和常见桌面程序时,没有必要为了“覆盖更多”而同时开启多个接管方式。
sniffing 如何帮助域名路由
sniffing 用于从连接中的协议特征恢复目标域名。某些应用先自行解析域名,再把 IP 地址交给代理;如果 routing 只有域名规则,内核看到纯 IP 时就无法按域名匹配。开启嗅探后,HTTP 请求中的主机信息或 TLS 握手中的服务器名称可以帮助路由模块获得域名。示例中的 destOverride 表示允许使用识别出的 HTTP 或 TLS 目标覆盖原始目的地址,以便后续规则判断。
嗅探不是 DNS 的替代品,也不是所有连接都能恢复域名。没有可识别主机信息的协议仍然只呈现 IP;加密握手方式和应用行为也会影响结果。排查路由未命中时,可以先看访问日志记录的是域名还是 IP,再决定调整 domainStrategy、增加 IP 规则或检查嗅探设置。不要在没有观察日志的情况下反复堆叠相同域名与 IP 条件,这会让规则难以维护。
端口、认证和标签的配置原则
同一个地址上的端口不能被两个进程同时占用,也不能让两个入站监听同一地址与同一端口。客户端启动后若立刻报告地址已被占用,先关闭重复运行的实例,再检查其他代理工具或旧内核进程。随意改端口只能解决冲突的一半:系统代理、浏览器扩展和局域网设备中的端口也必须同步修改。为了减少混淆,可以把 SOCKS 与 HTTP 端口保持相邻,但不要依赖某个固定数字判断协议类型。
auth: "noauth" 适合仅监听回环地址的本机 SOCKS 入站。监听局域网地址时,应结合客户端支持情况评估认证与防火墙限制,并只允许可信网络访问。标签方面,每个入站使用独立名称,后续就能通过 inboundTag 为不同入口设置不同路由。例如本机流量使用常规分流,局域网共享入口限制部分端口。标签修改后,要全文检查 routing 中的引用,避免规则仍指向旧名称。
| 参数 | 推荐理解 | 常见错误 |
|---|---|---|
listen |
决定连接来源范围 | 共享时仍写回环地址,或本机使用时开放到全部网卡 |
port |
应用连接内核的本地端口 | 与其他程序冲突,修改后未同步系统代理 |
protocol |
定义入站握手方式 | 应用选择 HTTP,实际连接 SOCKS 端口 |
tag |
供路由规则引用的内部名称 | 改名后 routing 仍使用旧标签 |
sniffing |
辅助恢复域名并参与分流 | 误认为开启后所有 IP 都能转换成域名 |
03 / OUTBOUNDS
outbounds 出站配置
代理、直连与阻断组成基础出口
出站定义内核把流量送往哪里。完整配置通常至少包含代理出口和直连出口,需要明确拒绝某类连接时再增加阻断出口。代理出口保存服务器地址、端口、用户标识、加密或传输设置;直连出口让内核直接访问目标;阻断出口则主动终止被规则匹配的连接。routing 不负责建立连接,它只负责把当前请求交给某个出站标签。
出站数组的顺序值得留意。当某条连接没有命中任何路由规则时,常见实现会使用第一个出站作为默认出口。因此,把代理放第一项还是把直连放第一项,会直接影响漏网流量的去向。不要只依赖默认顺序表达关键策略,重要流量应写清楚规则;同时仍要让第一项符合整体预期,防止新增域名或遗漏条件时产生意外结果。
{
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "11111111-2222-4333-8444-555555555555",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com"
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "none"
}
}
}
]
}
协议身份参数与传输参数要分开看
排查代理出站时,先把字段分成两组。第一组是协议身份参数,例如服务器地址、端口、用户 ID 和协议要求的附加设置;第二组是 streamSettings 中的传输参数,例如 TCP、WebSocket、gRPC、TLS 或 REALITY。两组参数分别正确但组合关系不一致,连接仍然无法建立。例如远端使用 WebSocket,而本地写成 TCP;服务器证书对应的名称与 serverName 不同;用户标识正确,但端口指向另一项服务。
订阅导入的价值之一,就是把服务提供方给出的协议、传输、安全层和主机参数一起写入客户端。手工迁移时不要只复制地址与端口。看到“节点能测试但网页打不开”时,也不要立即认定出站身份参数全部正确:客户端测试方法可能只覆盖部分链路,真实应用还会涉及 DNS、UDP、路由和系统代理。应结合运行日志判断失败发生在解析、连接远端、握手还是目标访问阶段。
直连出口同样会受到 DNS 与网络环境影响
freedom 表示由当前设备直接建立目标连接。它不是绕过整个配置流程,而是仍然经过入站和 routing 后,由内核执行直连。直连失败时要检查本地网络、系统 DNS、目标地址以及出站的域名策略。若规则根据域名选择 direct,但目标在建立连接前需要解析,解析结果和地址族会影响后续行为。某些环境中 IPv6 记录存在但实际连接条件不完整,也可能表现为等待较久后超时。
可以为 freedom 出站设置适当的域名解析策略,但不同内核支持的取值和行为可能有差异。没有明确需要时,先保留客户端生成的默认值。调试过程中若想判断问题是否来自分流,可以临时建立一条范围很小、目标明确的规则送往 direct,而不是把全部规则删除。验证完成后再恢复,避免临时测试改变其他应用的流量路径。
代理链与多出口要从简单结构开始
一个配置可以包含多个代理出站,并通过路由标签选择,也可以让一个出口经由另一个出口建立底层连接。这样的结构适合有明确链路需求的环境,但标签依赖会迅速增加。开始配置前先画出“入站 → 路由 → 第一出口 → 底层出口”的顺序,确保不存在相互引用。若 proxy-a 依赖 proxy-b,而 proxy-b 又回到 proxy-a,内核无法得到有效链路。
多节点选择通常由 v2rayN、v2rayNG 或 v2flyNG 的配置管理功能完成。客户端切换节点时,会调整当前使用的出站或重新生成运行配置。直接在生成文件中塞入大量服务器对象,不一定能与客户端的切换逻辑配合。桌面场景优先让 v2rayN 管理节点,只把稳定的自定义路由和 DNS 需求放到客户端支持的扩展位置,这比长期手工维护一整份节点清单更容易回退。
| 标签示例 | 协议 | 作用 | 排查重点 |
|---|---|---|---|
proxy |
按节点实际协议 | 连接远端服务器并转发目标流量 | 地址、端口、身份、传输与安全层必须成套一致 |
direct |
freedom |
从本机网络直接访问目标 | 本地网络、DNS、地址族和目标可达性 |
block |
blackhole |
终止匹配流量 | 规则范围是否过宽,是否误伤必要连接 |
04 / ROUTING
routing 路由规则
规则从上到下匹配,第一条结果生效
路由模块根据连接的目标域名、IP、端口、网络类型、协议特征或入站标签选择出站。最重要的行为是规则顺序:规则通常从上到下检查,一旦某条匹配,就使用该条指定的 outboundTag,后续规则不再参与。因此更具体的规则应放在前面,更宽泛的规则放在后面。把“所有 TCP 流量走代理”写在第一条,后面的直连域名规则就没有机会生效。
设计规则时,先写出默认策略,再列出例外。如果默认出口是代理,可以优先放置阻断条件和明确直连条件,其他流量落到默认代理;如果默认出口是直连,则先列出需要代理的目标。不要同时依赖出站数组顺序、复杂域名列表和多条兜底规则表达同一件事。选择一种清晰的默认行为,规则只描述例外,后续维护更容易判断新增条目应该放在哪里。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"protocol": [
"bittorrent"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"domain:intranet.example.com",
"full:printer.example.net"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
域名匹配方式决定规则边界
域名条件常见写法包括完整匹配、域名及其子域匹配、关键词匹配和预置域名集合。full:printer.example.net 只匹配完整主机名,适合边界明确的单一服务;domain:example.com 通常覆盖该域名及其子域,适合一组相关主机;没有前缀的字符串在不同语境下可能按特定方式解释,维护时最好显式写出匹配类型,避免日后忘记原意。
关键词匹配范围较宽,一个短字符串可能意外命中不相关域名。除非确实需要按名称片段归类,否则优先使用 full 或 domain。规则没有命中时,先确认内核看到的目标是不是域名。如果应用已经把目标解析为 IP,而入站嗅探没有恢复域名,那么再精确的域名规则也不会执行。此时可以检查访问日志、启用合适的 sniffing,或为已知地址范围补充 IP 条件。
domainStrategy 连接域名规则与 IP 规则
domainStrategy 控制路由模块在什么情况下为了匹配 IP 规则而解析域名。AsIs 强调按收到的目标形式判断,域名不会仅为了路由匹配而主动转成 IP;IPIfNonMatch 通常表示域名规则未命中后,再解析地址并尝试 IP 规则;其他策略可能更积极地进行解析。策略越积极,域名流量越可能参与 IP 分类,但也会增加 DNS 行为与路由结果之间的耦合。
选择策略时要先问:当前规则主要依赖域名还是 IP?如果大部分规则是明确域名,仅少数网段需要补充判断,IPIfNonMatch 比较容易理解。如果所有域名都要先按地址分类,则必须保证 DNS 配置与预期出口一致。否则同一域名因解析服务器、缓存或地址族不同得到不同结果,路由也会变化。修改 domainStrategy 后,应测试域名规则、IP 规则和未命中目标三类情况,而不是只打开一个网页判断成功。
IP、端口、网络与入站标签可以组合
IP 条件可以写单个地址、CIDR 网段或内核支持的预置集合。私有地址通常应直连,避免访问路由器、打印机或局域网服务时被送往远端。端口条件适合限制明确的服务范围,例如 53 或 80,443,也可以表达区间。网络条件常用 tcp、udp 或二者组合。多个不同字段放在同一条规则中时,通常需要同时满足;同一字段数组里的多个值则表示任一值命中。
inboundTag 很适合区分来源。例如 socks-in 走常规分流,lan-in 只允许访问指定出口。这样不必为每种来源启动多个内核实例。配置时应先确认入站标签真实存在,并把来源限制写在规则前部,避免被更宽的目标规则抢先匹配。对端口和协议做阻断时也要保守,范围过宽会表现为部分应用能打开首页,却无法播放、登录或同步。
用日志验证规则,不靠猜测
验证路由最有效的方法,是准备几个目标明确的测试项:一个应直连的内部域名、一个应进入代理的目标、一个应被阻断的条件,再查看访问日志中的出站标签。若日志只显示目标却不显示预期标签,可以临时提高日志详细程度,测试完成后再恢复到较克制的级别,避免日志持续增长。修改规则后要重启或重新加载内核,确认客户端没有继续使用旧的运行配置。
当规则数量变多时,给每组规则写在配置外部的维护说明,记录“为什么需要这条”,比只记录域名列表更有价值。标准 JSON 不能写注释,可在独立文档中保存说明。订阅更新一般影响节点与代理出站,不应顺手覆盖手工路由;如果客户端每次更新后都丢失规则,说明编辑位置可能是临时生成文件,应改用客户端提供的路由配置入口。
05 / DNS
dns 解析配置
先分清系统解析与内核解析
DNS 配置容易出错,是因为一台设备上可能同时存在多条解析路径。应用可以先调用系统 DNS 得到 IP,再把 IP 交给代理;内核也可以为了路由判断主动解析域名;TUN 场景还可能由客户端接管系统查询。配置文件中的 dns 主要定义内核自身如何解析,并不自动保证所有应用查询都经过这里。判断问题前,先确认日志中进入内核的是域名还是已经解析好的 IP。
如果应用把域名直接交给 SOCKS 或 HTTP 代理,内核有机会按自己的 DNS 配置处理。若应用在本地先解析,routing 看到的可能只有地址,此时 DNS 配置对该次原始查询不一定生效。sniffing 可以从部分连接中恢复域名,但不能替代完整的查询接管。因此“已经写了 dns 对象”与“所有程序都使用该 DNS”不是同一件事。
{
"dns": {
"hosts": {
"router.home.arpa": "192.168.1.1"
},
"servers": [
{
"address": "1.1.1.1",
"domains": [
"domain:example.com"
],
"skipFallback": true
},
"localhost"
],
"queryStrategy": "UseIP"
}
}
servers 数组既有顺序,也可以附带条件
servers 可以包含简单地址,也可以使用对象为某个服务器附加域名条件、期望地址范围或回退行为。简单配置从一两个稳定解析源开始即可。服务器越多,不代表解析越可靠;如果各服务器的使用条件不清楚,失败时很难判断查询实际发往哪里。对象中的 domains 用于让指定域名优先交给该服务器,适合内部域名或有明确解析来源的服务。
skipFallback 的目的,是控制匹配当前服务器条件的查询是否还参与后续回退。启用前要确认该服务器确实能够解析所列域名,否则查询失败后可能不会再尝试其他来源。对于局域网主机名,直接使用本地解析服务器或 hosts 静态映射通常更清楚。把内部名称交给公共解析源,不仅得不到结果,还可能让排查方向偏离本地网络。
hosts 适合稳定映射,不适合维护动态地址
hosts 可以把域名映射到固定地址,也可以用于少量别名关系。它在测试新服务、覆盖局域网主机名或临时绕开错误解析时很方便。由于映射优先于普通查询,写错后会持续把连接送往错误目标。使用 hosts 排错时,要记录新增项并在验证后决定是否保留,避免数周后地址已经变化,配置仍固定在旧值。
映射值的数据形态要符合内核要求,域名键也应写成预期的完整名称。若目标同时有 IPv4 与 IPv6,单一固定映射会改变正常的地址选择。对于由服务方动态调度的域名,不建议用 hosts 长期固定某个结果;看似缩短了一次查询,实际可能失去故障切换和地址更新能力。遇到偶发连接问题,应先比较解析结果与连接日志,而不是立刻把当前 IP 写死。
queryStrategy 影响地址族选择
queryStrategy 用来控制查询 IPv4、IPv6 或两类地址的倾向。不同内核支持的具体取值可能有所差异,应以当前客户端所用内核的有效配置为准。设备所在网络只有稳定 IPv4 时,强制只返回 IPv6 会导致目标不可达;网络具备 IPv6 并不表示每条远端链路都适合优先使用它。选择策略时要结合本地网络、代理服务器地址和目标出站的能力。
典型现象是域名解析很快,但连接在某个地址族上持续等待,随后回退或超时。此时可以分别查看解析得到的 A 与 AAAA 记录,再观察内核实际尝试的目标地址。不要把所有 timeout 都归为节点故障。若切换查询策略后恢复,应继续确认是本地 IPv6 路由、远端服务器监听还是目标网络路径的问题,而不是永久依赖一个偶然有效的设置。
DNS 与 routing 需要闭环检查
当 domainStrategy 需要解析域名以匹配 IP 规则时,routing 会调用 DNS;解析查询本身又可能通过某个出站发送。设计不当会出现循环依赖:为了决定域名走哪个出口先发起查询,但查询出口又依赖尚未完成的域名分类。简单环境应避免给 DNS 设计过度复杂的路由链。先确保基础查询可用,再为明确的解析服务器地址添加直连或代理规则。
检查闭环可以按四步进行:第一,看应用交给入站的是域名还是 IP;第二,看路由策略是否需要解析;第三,看查询由哪个服务器处理;第四,看查询连接本身通过哪个出站。任何一步与预期不同,最终都会表现成网页打不开或分流错误。v2rayN 的日志可以帮助定位查询和连接阶段,阅读方法可参考V2Ray 运行日志怎么看。
| 现象 | 优先检查 | 不要先做什么 |
|---|---|---|
| 域名失败,直接访问 IP 有响应 | 查询服务器、DNS 出站路径、应用是否使用系统解析 | 一次加入很多解析服务器 |
| 域名规则不命中 | 入站看到域名还是 IP、sniffing、domainStrategy | 重复添加相同域名关键词 |
| 局域网主机名无法解析 | 本地 DNS、hosts 映射、搜索域 | 交给与局域网无关的解析源 |
| 解析成功但连接长时间等待 | 地址族、目标路由、出站实际尝试的地址 | 只根据解析速度判断节点状态 |
06 / POLICY
policy 策略与统计
policy 控制运行行为,不决定分流方向
policy 经常被误认为 routing 的补充,实际它主要控制连接会话的超时、空闲判定和统计开关。流量走代理还是直连,仍由 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 处理不同阶段
handshake 约束连接建立阶段允许等待的时间。它针对的是尚未完成握手的连接,不等同于网页整体加载时限。设置过短时,在网络波动或远端响应稍慢的情况下会提前失败;设置过长则会让明显无法建立的连接占用资源更久。看到握手超时时,应先排查服务器地址、端口、传输层和本地网络,而不是立刻把数值调得很大。
connIdle 关注连接在没有数据活动时保留多久。空闲连接被关闭后,应用通常会重新建立,但某些程序会把它表现为会话中断。调试时可以比较问题发生的时间间隔是否稳定:如果每次都在相近的空闲时长后断开,策略值得检查;如果断开时间随机且日志显示远端重置,则更可能是链路或服务端行为。
uplinkOnly 和 downlinkOnly 用于处理只有单方向数据活动的连接。它们不是上传、下载速度限制,也不会给某个应用分配带宽。不了解现有连接行为时,不建议为了“优化”而随意缩短。图形客户端生成的默认策略通常适合普通使用,只有长期连接、资源约束或明确的服务场景才需要单独评估。
统计开关只负责采集许可
statsUserUplink、statsUserDownlink 以及 system 下的入站、出站统计字段,用于允许内核记录对应方向的流量信息。打开这些布尔值不一定会自动出现可见图表或界面数字,还需要配置支持的统计模块与查询方式。若客户端没有消费这些数据,单纯打开全部统计项只会增加不必要的状态维护。
不要把统计项当作连接成功检测。一个方向出现字节变化,只表示曾有数据经过对应计数范围,无法单独证明目标内容完整返回,也无法说明路由选择符合预期。判断连接质量仍应结合访问结果与错误日志。客户端界面展示的流量统计可能来自系统接口、内核接口或自身计数,具体口径未必与 policy 中每个开关完全一致。
多用户等级需要明确关联关系
当配置包含多个用户对象时,可以为用户指定不同 level,再在 policy 的 levels 中定义对应策略。等级键在 JSON 中以字符串形式出现,例如 "0"、"1"。如果用户引用了一个没有配置的等级,内核可能采用默认行为或报告相关问题,具体取决于实现。维护时应把用户等级和策略等级一起检查,避免只复制其中一半。
普通客户端出站通常不需要复杂的等级体系。节点订阅提供的用户身份主要用于远端协议认证,并不意味着本地一定要为每个节点创建 policy 等级。只有作为入站服务、需要区分会话策略时,多等级才更常见。本页聚焦客户端配置,因此建议保持单一默认等级,把精力放在入站安全、出站参数和路由可读性上。
日志级别与策略排查要配合
策略问题经常表现为“连接建立后又断开”,需要日志提供时间线。日常运行可使用 warning 等较克制的级别;排查期间再临时提高详细程度,并记录开始时间和复现步骤。日志路径如果写入无权限目录,内核可能无法启动或无法留下诊断信息。图形客户端通常已经处理日志位置,手工配置独立核心时才需要特别检查文件路径。
复现后先比较三个时间点:连接开始、最后一次数据活动、连接关闭。若关闭紧跟策略阈值,可调整一项后再次测试;若日志明确由远端关闭或底层连接失败,policy 并不是主要方向。完成调试后恢复合理日志级别,并删除仅为测试开启的统计项,保持运行配置简洁。
| 字段 | 控制阶段 | 不负责的事情 |
|---|---|---|
handshake |
连接握手等待 | 网页完整加载时长 |
connIdle |
无数据活动的连接保留 | 网络速度限制 |
uplinkOnly |
仅上行活动后的连接处理 | 上传带宽分配 |
downlinkOnly |
仅下行活动后的连接处理 | 下载带宽分配 |
statsInboundUplink |
允许记录入站上行统计 | 自动生成可视化报告 |
07 / ASSEMBLY
组合完整配置与启动前检查
先构建最小闭环,再逐层增加能力
组合配置时,最可靠的顺序是先建立最小闭环:一个仅监听本机的 SOCKS 入站、一个有效代理出站、一个直连出站,以及少量方向明确的路由规则。最小配置能够启动并完成连接后,再增加 HTTP 入站、DNS 条件、阻断规则和 policy。这样每次新增的范围有限,出现问题时可以直接回退到上一份可用配置。
完整文件中的每个标签都要形成引用闭环。routing 使用的 outboundTag 必须能在 outbounds 中找到;inboundTag 必须与 inbounds 的标签一致;用户 level 若关联 policy,也要存在对应策略。标签区分大小写时,Proxy 与 proxy 会被视为不同名称。建议只使用小写字母、数字和短横线,减少输入错误。
{
"log": {
"loglevel": "warning"
},
"dns": {
"servers": [
"localhost"
],
"queryStrategy": "UseIP"
},
"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": "11111111-2222-4333-8444-555555555555",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com"
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
},
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300
}
}
}
}
示例完整不等于节点参数可以直接使用
上面的 JSON 层级完整,可以用于理解各部分如何组合,但其中的服务器域名和用户 ID 是文档示例。实际配置必须替换为自己订阅或服务信息中的完整参数,并让 streamSettings 与远端一致。若实际节点使用的不是示例中的协议或传输方式,应替换整个代理出站对象,而不是只改协议名称。协议对象内部结构不同,简单改一个字符串会留下不兼容字段。
使用 v2rayN、v2rayNG 或 v2flyNG 时,优先导入节点后观察客户端生成的出站结构,再把需要的路由思想应用到客户端支持的位置。不要为了使用本文示例而放弃客户端已经正确生成的节点参数。配置参考的用途是解释结构和帮助排错,不是让每位用户都从空文件手写全部连接信息。
执行语法检查与内核配置检查
第一层检查可以使用支持 JSON 的编辑器确认括号、引号和逗号。第二层需要让实际内核读取配置。独立运行 Xray 时,常见测试方式是执行 xray run -test -config config.json;独立运行 V2Ray 时,可根据当前可执行文件支持的命令使用 v2ray test -c config.json。命令名称和参数应以本机内核帮助输出为准,因为客户端封装方式和可执行文件位置可能不同。
图形客户端用户通常不需要手工打开终端测试临时配置。重新启动内核后查看客户端日志即可。若客户端启动前会重新生成文件,应在它提供的编辑入口中保存改动。测试结果报告未知字段时,先确认当前是 V2Fly 还是 Xray 内核,再检查该字段属于顶层、入站设置、协议设置还是 streamSettings。把正确字段放错层级,同样会被判定无效。
按数据流做启动后的四段验证
配置通过读取后,还要验证运行链路。第一段检查入站:确认端口正在监听,应用代理类型与端口对应。第二段检查路由:访问一个目标,查看日志选择了 proxy 还是 direct。第三段检查出站:观察远端连接与握手是否完成。第四段检查目标响应:确认应用拿到实际内容,而不是仅建立了本地代理连接。
如果第一段失败,重点看端口占用和监听地址;第二段错误,检查规则顺序、目标形式和标签;第三段失败,检查节点、网络和传输参数;前三段正常但第四段异常,再看 DNS、目标服务和应用自身行为。这种分段方法比不停更换节点更有效,也能避免把本地端口问题误判为远端故障。
客户端覆盖配置时如何保留改动
v2rayN 在切换服务器、更新订阅或改变代理模式后,可能重新组织内核运行配置。需要长期保留的内容,应放进客户端支持的自定义路由、DNS 或自定义配置功能,而不是只编辑运行目录里的临时 JSON。修改前先导出或记录当前设置,更新后再确认自定义规则仍被合并。首次安装与配置文件位置相关的注意事项,可查看v2rayN 首次安装与初始设置全流程。
Android 客户端也可能把单节点配置、订阅条目和运行配置分开保存。编辑某个节点只会改变该节点的协议参数,不一定改变全局路由。先确认当前页面修改的是节点、路由还是应用设置,再测试结果。v2rayNG 首推使用 Xray 内核路径,v2flyNG 作为 v2fly 内核备选;两者扩展字段存在差异时,不应直接互相复制完整 JSON。
08 / TROUBLESHOOTING
配置错误与连接故障排查
启动即失败:先看第一条明确错误
内核启动失败时,日志后面可能跟着多条连锁信息,真正原因通常出现在最早的一条明确错误附近。常见类型包括 JSON 解析失败、未知字段、数据类型不符、端口占用、文件路径不可访问,以及被 routing 引用的标签不存在。先处理第一处错误,再重新启动;不要一次根据后续信息修改多个区域,因为后续报错可能只是前一处失败的结果。
JSON 解析错误通常会给出行号或字符位置。检查该行前后是否少了逗号、多了尾逗号、引号没有闭合,或复制时混入了全角标点。错误位置有时指向解析器发现问题的地方,而真正遗漏可能在上一行。若文件很长,可以把最近新增的整个对象暂时移除,确认基础配置恢复后,再把片段逐层放回。
内核运行但应用无法连接本地代理
这种情况先不检查远端节点。确认应用代理地址是否为 127.0.0.1,端口是否与入站一致,代理类型是否匹配。若使用系统代理,检查客户端是否已经启用相应模式;仅启动内核不一定会自动修改系统设置。浏览器扩展、应用内代理和系统代理同时存在时,可能形成重复代理或指向旧端口,测试时应保留一条清晰路径。
在 Windows、macOS 或 Linux 桌面环境中,端口被旧进程占用并不少见。退出客户端后确认内核进程是否随之结束,再重新打开。若修改了入站端口,系统代理也要同步更新。Android 客户端使用系统提供的网络接口接管应用流量,排查重点与桌面本地 SOCKS 端口不同,应先查看客户端是否处于已连接状态以及运行日志是否成功启动内核。
本地代理可连接,但远端握手失败
日志出现连接被拒绝、握手失败或远端提前关闭时,按“地址与端口 → 用户身份 → 协议 → 传输 → 安全层”的顺序检查。域名能解析不代表端口对应正确服务,TCP 能建立也不代表 TLS 名称和应用层传输一致。订阅节点应先执行一次正常更新,确认当前条目没有使用旧参数;手工节点则逐项与原始配置信息比较。
系统时间明显不正确会影响依赖时间的安全连接,应先让设备时间恢复正常。网络切换后若问题消失,说明还要检查当前网络、DNS 或地址族,而不是只修改协议。节点超时可以按节点超时排查顺序逐层验证,避免跳过本地网络和系统时间,直接反复改出站对象。
只有部分网站或应用失败
部分目标失败通常说明基础入站和至少一个出站已经可用,接下来重点看路由、DNS、UDP 与目标特征。先比较成功目标和失败目标分别使用哪个出站,再查看失败项进入内核时是域名还是 IP。如果错误规则把某个域名送往 direct,节点本身再正常也不会参与这次连接;如果 domainStrategy 触发了不同地址解析,结果也可能与预期域名规则不一致。
应用登录、语音、视频或同步功能可能使用不同域名、端口与网络类型。首页可以打开,只能说明其中一部分请求成功。不要根据主页面结果把整个应用域名归到一条过宽规则。复现时记录失败功能对应的日志目标,逐个补充必要条件。涉及 UDP 时,检查 SOCKS 入站是否允许 UDP、代理协议与服务端是否支持当前路径,以及 routing 是否把 UDP 送往正确出口。
规则看起来正确但始终不命中
先确认规则位置。前面是否存在更宽的 domain、IP、network 或 port 条件?其次确认目标形式:日志看到的是完整域名、子域、IP,还是经 sniffing 恢复的名称?然后检查匹配前缀是否符合需求,full 不会自动覆盖所有子域,关键词又可能太宽。最后检查 outboundTag 拼写和当前运行文件,避免改的是备份文件,客户端实际加载的是另一份配置。
为了验证某条规则,可以暂时把它移到前部,并将目标限制为一个明确域名。测试后查看日志中的出站标签。如果仍不命中,问题在目标形式或配置未加载;如果移到前部后命中,说明原位置之前有规则截获。确定原因后重新整理顺序,不要长期依赖把所有新规则都堆到最上方,否则具体规则之间也会逐渐互相覆盖。
连接一段时间后断开
先判断断开是否发生在稳定时间间隔。若每次都接近 connIdle 或单向连接策略的时间,检查 policy;若时间随机,查看远端重置、网络切换、设备休眠和地址变化。笔记本从一个网络切到另一个网络后,旧连接失效是正常现象,客户端通常需要重新建立链路。不要把一次睡眠唤醒后的中断直接归因于节点参数。
日志中的 timeout、context canceled 或 connection reset 代表不同阶段和触发方,不能只看到“错误”就采用同一种处理。timeout 需要结合前一条记录判断是 DNS、拨号还是握手;context canceled 可能来自上层请求主动结束;reset 表示连接被某一端重置。先找时间线上最早异常,再判断后续错误是否只是取消和清理动作。
建立可重复的排查记录
复杂配置最好保留一份简短记录,包含客户端名称、当前内核家族、入站端口、默认出站、最近修改区域和复现步骤。记录不需要保存节点敏感信息,只要能说明结构。每次测试写下“改了什么、预期什么、实际日志是什么”,两三轮后通常就能排除大部分猜测。反复切换多个选项却不记录,容易在问题偶然消失后也无法确认原因。
需要恢复时,先回到最小可用配置,再逐项加入 DNS、分流和策略。若最小配置仍失败,问题更可能位于客户端安装、本地网络或节点本身,可回到快速上手主线重新确认导入与连接步骤。若只有自定义规则失败,则保留已验证的节点出站,集中检查 routing 和目标日志,不必重新安装客户端。
| 故障层 | 典型现象 | 优先动作 |
|---|---|---|
| JSON 与字段 | 内核无法启动 | 处理第一条解析或字段错误,检查最近改动 |
| 入站 | 应用无法连接本地代理 | 核对地址、端口、协议类型与端口占用 |
| 路由 | 目标走错出口或规则不命中 | 查看目标形式、规则顺序和实际出站标签 |
| DNS | 域名失败或解析结果异常 | 确认查询路径、服务器条件和地址族 |
| 出站 | 远端拒绝、握手失败或超时 | 成套核对地址、身份、协议、传输和安全层 |
| 策略与会话 | 连接在固定空闲时间后断开 | 对照 policy 阈值与日志时间线 |