V2Ray 与 Xray 配置文件的核心任务,是把一条连接从“应用发出的本地请求”转换为“由指定出口处理的网络请求”。配置并不是若干独立字段的简单集合,而是一条有明确先后顺序的数据路径:应用先连接入站监听端口,内核读取目标地址并执行流量探测,路由模块根据域名、IP、端口或入站标签选择出站,DNS 模块在需要时参与解析,最后由对应出站建立连接。理解这条路径后,很多看似随机的故障都可以还原为某个环节没有获得预期信息。
v2rayN 是 Windows、macOS 与 Linux 桌面端的主要图形客户端,v2rayNG 与 v2flyNG 分别面向 Android。图形客户端通常会根据界面选项生成运行配置,因此直接编辑临时配置可能在下一次启动或切换服务器后被覆盖。长期设置应优先通过客户端提供的路由、DNS、参数设置或自定义配置入口完成;需要选择安装包时可前往下载页,只需要完成首次连接时则应先走快速上手主线。
JSON 结构总览与配置加载顺序
顶层对象如何协同工作
完整配置以一个 JSON 对象作为根节点。常见顶层字段包括 log、dns、inbounds、outbounds、routing、policy 与 stats。其中,入站和出站是连接路径的两端,路由负责把两端关联起来;DNS 为域名匹配与目标解析提供结果;策略模块控制超时、统计和不同用户等级的行为;日志字段则决定运行时留下多少诊断信息。配置可以缺少某些可选模块,但至少要有能够接收请求的入站和能够处理请求的出站,否则内核即使启动,也无法形成完整的数据路径。
数组顺序和标签同时影响配置行为。每个入站或出站都可以通过 tag 获得稳定名称,路由规则再使用 inboundTag 或 outboundTag 引用它。标签只是配置内部标识,不是服务器名称,也不会改变协议本身。建议使用简短、语义固定的英文标签,例如 socks-in、proxy、direct 与 block。同一作用域内不要复用标签,否则阅读配置时难以判断规则最终指向哪个对象,部分实现还可能直接拒绝加载。
{
"log": {
"loglevel": "warning"
},
"dns": {
"servers": [
"1.1.1.1",
"localhost"
]
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"udp": true
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
}
]
}
}
JSON 语法与数据类型
JSON 对格式的要求比许多配置语言严格。对象使用花括号,数组使用方括号,键名与字符串必须放在英文双引号中;布尔值只能写成小写的 true 或 false,数字不能额外加引号。对象最后一个字段和数组最后一个元素后面不能保留逗号。标准 JSON 也不接受注释,因此不要把说明文字直接写进将要加载的配置。需要维护备注时,可以在外部文档记录,或使用客户端专门提供的备注字段;自行添加内核不认识的字段,可能被忽略,也可能在严格解析模式下触发错误。
字段的数据类型不能只凭外观看起来接近就替换。例如端口通常是数字 10808,而不是字符串 "10808";域名列表必须是数组,即使只有一项,也应写成 ["domain:example.com"]。规则中的 port 则常用字符串表达范围,如 "53" 或 "80,443,1000-2000"。这类差异来自字段定义,而不是统一语法。编辑前应先确认字段属于数字、字符串、布尔值、对象还是数组,避免配置能够通过 JSON 解析,却在内核读取字段时失败。
配置加载与连接处理顺序
内核加载配置时,首先完成 JSON 解析与模块初始化,然后绑定入站监听地址。端口已被其他程序占用、监听地址不属于本机、字段类型错误,都会让启动阶段提前终止。启动成功只代表配置结构和本地资源基本可用,并不代表远端协议参数一定正确。真正的远端连接通常在应用请求到来后才建立,因此“内核已启动”和“目标可以访问”是两个不同的检查阶段。
请求进入后,内核先确定入站标签、目标地址、目标端口和网络类型。启用 sniffing 时,还可能从 HTTP 请求或 TLS 握手中识别域名。随后 routing 从上到下检查规则,通常由第一条完整匹配的规则决定出口;若没有规则命中,则使用默认出站,默认出站一般与出站数组的首项或客户端生成逻辑有关。DNS 是否介入,取决于目标是否需要解析以及 domainStrategy 的选择。最后,出站模块根据协议、传输层、安全层和服务器参数建立连接。排查时沿着同样的顺序检查,比反复切换选项更有效。
配置维护应保持单一职责:入站只描述本地接入方式,出站只描述出口能力,路由只表达选择条件,DNS 只处理解析路径,policy 只控制连接生命周期和统计。把多个目的混在一条规则中,短期可能减少行数,长期却会增加规则覆盖和回归测试的难度。建议每次只修改一个模块,保存前确认 JSON 语法,启动后查看 warning 或 info 级别日志,再用明确的域名、IP 和端口场景逐项测试。
inbounds 入站:监听地址、端口与流量探测
入站负责接收什么
inbounds 是入站对象数组,每个对象描述一种本地接入方式。桌面客户端最常见的是 SOCKS 入站和 HTTP 入站:支持 SOCKS 的应用连接 SOCKS 端口,只支持 HTTP 代理的应用连接 HTTP 端口;系统代理模式则通常由客户端把操作系统代理设置指向其中一个本地端口。透明接管、虚拟网卡或重定向入站涉及额外的平台权限与网络栈配置,不应与普通本地代理端口混为一谈。
listen 决定监听在哪个本地地址。写成 127.0.0.1 时,只接受本机连接,是个人桌面环境的常见选择;写成 0.0.0.0 时,会在所有可用的 IPv4 接口上监听,局域网内其他设备可能访问该端口。v2rayN 中“允许来自局域网的连接”一类选项,本质上会影响监听范围以及相关防火墙条件。只有明确需要为同一局域网的其他设备提供入口时,才应扩大监听范围,并同步确认操作系统防火墙和网络环境。
port 必须是本机未被占用的有效端口。常见的本地 SOCKS 监听端口是 10808,但它不是协议强制值,可以根据本机环境调整。修改后,浏览器、开发工具、系统代理或其他调用方也必须同步更新;只改内核端口而不改应用设置,会表现为应用无法连接本地代理。多个入站不能绑定同一地址上的同一端口,即使协议不同也会发生冲突。
{
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"],
"routeOnly": true
}
},
{
"tag": "http-in",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
]
}
SOCKS、HTTP 与 UDP 行为
SOCKS 入站的 settings.udp 决定是否接受 UDP 请求。启用后并不意味着所有应用都会自动使用 UDP,也不保证对应出站和远端协议能够处理所有 UDP 场景。应用必须通过兼容方式把 UDP 请求交给 SOCKS 入站,路由规则也不能将其误送到不适合的出口。排查“网页正常但部分实时应用异常”时,需要分别确认应用接入方式、入站 UDP 开关、路由网络条件和出站协议能力。
HTTP 入站主要接收 HTTP 代理请求,以及通过 CONNECT 方法建立的 HTTPS 隧道。它不是普通网页服务器,也不会自动处理任意发送到该端口的协议。部分应用只读取系统 HTTP 代理设置,部分应用支持独立 SOCKS 设置,还有一些应用完全忽略系统代理。配置入站时应先确认调用方实际支持哪种接入方式,而不是同时增加很多监听端口。端口越多,排查端口占用、规则来源和防火墙行为时越复杂。
当监听地址扩大到局域网时,可以在入站设置中考虑认证,但认证能力取决于具体入站协议和客户端生成方式。更稳妥的做法是先限制网络边界,只允许受控设备访问,并避免将本地代理端口暴露到不可信网络。若仅用于本机,保持回环地址通常足够。Windows、macOS 与 Linux 对防火墙提示和网络权限的呈现不同,但判断原则一致:先确认内核确实监听预期地址,再确认调用设备能够到达该地址和端口。
sniffing 如何辅助路由
流量探测 sniffing 用于从连接内容中识别目标域名,常见识别来源包括 HTTP Host、TLS Server Name 和 QUIC 中可见的目标信息。它的价值在于:应用可能先把域名解析为 IP,再把纯 IP 目标交给代理;如果路由只看到 IP,geosite 或域名后缀规则就无法命中。启用探测后,内核可以用识别到的域名参与路由,让域名规则获得更稳定的输入。
destOverride 指定允许从哪些协议特征覆盖或补充目标信息,常用值为 http、tls 和 quic。routeOnly 为 true 时,探测结果主要用于路由判断,不直接改写最终连接目标,这有助于减少目标替换带来的副作用。是否启用该项应结合实际规则设计:如果只使用 IP 规则,探测的收益有限;如果大量使用 geosite、完整域名和后缀规则,探测通常更有价值。
探测不是通用解密,也不是所有连接都能识别。加密应用协议、非标准握手、直接访问 IP 或提前建立的复用连接,都可能无法提供可用域名。规则设计不能假设每条连接必然得到探测域名,应保留合理的 IP 规则与默认出口。出现域名规则偶尔不命中时,可先把日志等级临时调整为 info,比较应用原始目标、探测结果和最终出站标签;完成诊断后再恢复 warning,避免长期积累过多日志。
多个入站还可以通过不同标签配合路由。例如将浏览器指向 browser-in,将开发工具指向 dev-in,再用 inboundTag 为两类请求选择不同出口。这样比按进程名匹配更容易跨平台复用,但前提是各应用能够设置独立代理端口。若使用 v2rayN 的系统代理模式,通常只需要保留客户端生成的标准入站;只有存在明确隔离需求时,才增加自定义入口。
outbounds 出站:协议参数、标签与传输层
出站数组与默认出口
outbounds 描述连接离开内核时采用的处理方式。代理协议出站负责连接远端服务器,freedom 出站用于直接访问目标,blackhole 出站用于终止匹配连接。实践中通常至少保留 proxy、direct 和 block 三个语义清晰的标签,让路由规则可以分别表达代理、直连和阻断。标签名称可以自定,但规则中的 outboundTag 必须与之完全一致,包括大小写。
没有命中路由规则时使用哪个出口,需要结合内核行为和客户端生成方式判断。许多配置把主要代理出站放在数组首位,使其成为未匹配流量的默认处理路径;另一些客户端会额外生成兜底规则。阅读实际运行配置时,不能只看界面里显示的服务器,还要查看出站顺序和路由末尾是否存在 catch-all 规则。若希望行为明确,可以在规则末尾加入网络范围完整的兜底条件,但应避免一条过宽规则提前截获所有流量。
{
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "11111111-1111-4111-8111-111111111111",
"encryption": "none",
"flow": "xtls-rprx-vision"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"serverName": "www.example.com",
"fingerprint": "chrome",
"publicKey": "dGVzdC1wdWJsaWMta2V5LWZvci1kb2N1bWVudA",
"shortId": "0123456789abcdef",
"spiderX": "/"
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIP"
}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "none"
}
}
}
]
}
以上代理参数使用文档示例地址与示例凭据,只用于展示字段层级,不能直接建立实际连接。真实配置中的地址、端口、用户标识、传输方式、安全层参数必须作为一组保持一致。订阅导入通常会自动生成这些字段;手工调整时,不应只根据协议名称替换单个值,因为同一协议还可能组合 TCP、WebSocket、gRPC、TLS、REALITY 和不同流控方式。
协议设置与 streamSettings 的分工
protocol 决定应用层代理协议,settings 保存该协议自身需要的服务器和用户信息;streamSettings 则描述底层传输网络与安全层。以 VLESS 为例,服务器地址、端口和用户标识位于 settings.vnext,TCP、WebSocket 或 gRPC 位于 streamSettings.network,TLS 或 REALITY 位于 streamSettings.security。这几个层级彼此关联,却不能交换位置。
VMess、VLESS、Trojan 与 Shadowsocks 的用户字段结构不同。VMess 常见用户信息包含 id 和安全设置;VLESS 使用 id、encryption,并可能配合 flow;Trojan 使用密码;Shadowsocks 使用加密方法与密码。客户端订阅能够减少手工录入错误,但导入后仍应核对协议、传输类型、TLS 服务器名称和端口是否完整。若订阅更新失败或分享链接格式异常,可参照订阅更新失败自查清单逐项确认。
mux 多路复用用于让多个逻辑连接共享较少的底层连接。它不是任何环境下都应开启的速度开关,是否有收益取决于协议、传输、服务器配置和业务类型。某些长连接或对时序敏感的请求可能不适合额外复用。出现连接建立正常但持续传输不稳定时,可以把 Mux 作为独立变量关闭测试,而不是同时修改协议、安全层和路由。
direct、block 与出口约束
freedom 出站直接连接目标,常用于私有地址、本地区域域名或明确希望由本地网络处理的请求。它仍然会受到本机 DNS、网络路由和防火墙影响,因此“direct”只表示不经过代理协议,并不保证目标一定可达。settings.domainStrategy 可控制 freedom 遇到域名时如何处理解析,具体选择应与顶层 DNS 和 routing 的域名策略协调,避免同一域名在不同阶段得到不一致结果。
blackhole 不向目标建立正常连接,适合阻断已知不需要的域名、IP 或端口。阻断规则应尽量具体,并放在需要优先执行的位置。过宽的阻断条件可能让更新、登录或局域网服务表现为超时。调试时可以暂时把可疑规则的出口改为 direct 或单独标签,确认是否由规则导致,再恢复预期行为。
部分配置会使用 sendThrough 指定出站连接从某个本地地址发出,或使用 sockopt 调整底层套接字选项。这类字段适合多网卡、特定路由表或高级网络环境,不应作为普通连接故障的第一处理手段。若地址并未分配给本机接口,出站会直接失败。桌面端首先应保持客户端默认值,只在能够明确描述目标网卡、地址族和路由需求时才增加绑定。
| 出站角色 | 常用 protocol | 主要用途 | 常见检查点 |
|---|---|---|---|
| 代理出口 | vless、vmess、trojan、shadowsocks | 按远端协议建立连接 | 地址、端口、用户参数、传输与安全层是否一致 |
| 直接连接 | freedom | 使用本地网络访问目标 | 本机 DNS、默认路由、防火墙与地址族 |
| 阻断连接 | blackhole | 终止命中规则的请求 | 规则范围与顺序是否过宽 |
维护出站时应优先保持标签稳定。路由规则引用的是标签而不是数组位置,稳定标签可以让服务器参数更新与路由策略解耦。切换订阅节点后,客户端可能重建代理出站,但 direct 和 block 的语义通常不需要变化。若自定义配置引用了客户端可能改名的内部标签,应在每次更新后检查实际生成结果,避免规则指向不存在的出口。
routing 路由规则:匹配顺序、域名与 IP 分流
规则按顺序匹配
routing.rules 是路由规则数组。常用规则类型为 field,可以组合域名、IP、端口、网络类型、入站标签、协议和用户等条件。规则从上到下检查,较具体、优先级较高的条件应放在前面,范围较宽的规则放在后面。若一条规则已经匹配,请求通常不会继续寻找更靠后的替代规则,因此顺序本身就是策略的一部分。
同一条 field 规则里的不同条件通常形成“同时满足”的关系。例如同时写入 domain 与 port,表示域名条件和端口条件都满足时才使用该出口;同一个数组内部的多个域名值则通常形成“任一命中”的关系。把多个不相关条件塞进同一条规则,容易误以为它们彼此独立。更清晰的做法是按业务目的拆分规则,并为每条规则保留单一可解释的命中原因。
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"domainMatcher": "hybrid",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"geosite:cn",
"domain:example.cn",
"full:service.example.cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["geoip:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:category-ads-all"],
"outboundTag": "block"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
该示例先处理私有 IP,再处理指定域名和区域域名,随后处理区域 IP,接着阻断特定分类,最后把剩余 TCP 与 UDP 请求交给 proxy。实际使用时,阻断规则是否应放在区域直连之前,取决于分类数据与目标策略;如果一个域名同时属于两个集合,位置更靠前的规则会取得控制权。修改规则顺序前,应列出可能重叠的集合,而不是只根据规则名称判断。
domainStrategy 决定何时解析
domainStrategy 控制路由模块在域名规则未能直接给出结果时,是否把域名解析为 IP 再尝试 IP 规则。AsIs 通常只使用当前已有的目标形式,域名目标不会为了匹配 IP 规则而主动解析;IPIfNonMatch 会先尝试域名规则,在没有匹配时解析 IP,再检查 IP 规则;IPOnDemand 会在路由过程中更积极地准备 IP 结果。具体行为还会受内核实现和配置组合影响,但选择原则是明确的:只有需要让域名目标参与 geoip 或 CIDR 规则时,才需要在路由阶段引入解析。
解析并非没有成本。它会增加 DNS 查询,也可能让路由结果受解析服务器、缓存和地址族影响。若所有重要目标都能由 geosite、完整域名或后缀规则覆盖,AsIs 更容易理解;若依赖 geoip:cn 或自定义 CIDR 对域名目标分流,则 IPIfNonMatch 通常更合适。不要仅因为某个模板使用了特定值就照搬,应根据规则中是否存在 IP 条件以及应用是否提交域名来选择。
启用 sniffing 后,路由可能获得从流量中识别的域名;未启用时,应用若提交的是 IP,域名规则没有可匹配对象。反过来,应用提交域名时,IP 规则是否参与又取决于 domainStrategy。由此可见,入站探测、路由域名策略和 DNS 并非三个孤立开关。排查规则时需要记录请求最初是域名还是 IP、探测是否得到域名、路由是否触发解析,以及最终拿到哪些 IP。
域名、IP、端口与标签条件
域名规则常见写法包括 full:、domain:、regexp: 和 geosite:。full:example.com 只匹配完整域名;domain:example.com 可覆盖该域名及其子域;正则表达式提供更灵活的模式,但复杂表达式会降低可读性,也更容易产生意外匹配;geosite 使用分类数据集合,适合维护范围较大的规则。单个明确站点优先使用 full 或 domain,只有集合规模较大时再使用分类数据。
IP 规则可写 CIDR,例如 192.168.0.0/16,也可以引用 geoip:private 与其他数据集合。私有地址规则通常应较早直连,否则局域网管理页、文件服务和本地开发环境可能被送往代理出口。需要注意,域名解析到私有地址时是否命中该规则,仍取决于路由是否执行了解析。仅添加 private 规则不能自动解决所有局域网域名问题。
port 支持单端口、逗号列表与范围,network 常用 tcp、udp 或二者组合。端口只描述连接目标端口,不等同于应用类别。大量服务可能共用 443,单靠端口无法判断具体域名;53 也可能承载不同形式的 DNS 请求。端口规则适合表达明确网络策略,不适合替代域名识别。
inboundTag 可以根据请求来自哪个入站进行分流,这对于多个本地端口的隔离很实用。protocol 条件则依赖内核识别结果,例如在探测后识别特定协议。使用这些高级条件时,应保留末尾兜底规则,防止未识别流量没有明确出口。路由修改完成后,至少测试私有 IP、明确直连域名、明确代理域名、普通未分类域名和 UDP 请求五类场景,并查看实际出站标签。
v2rayN 的路由设置界面通常会把预设、规则集和当前代理模式组合成最终配置。界面里选择“全局”或其他模式时,可能改变默认出口或生成额外规则,因此手工片段与客户端模式应一起核对。需要理解不同协议与路由场景的取舍时,可继续阅读VMess、VLESS、Trojan、Shadowsocks 协议对比。
DNS 配置:解析服务器、匹配域与地址族
内置 DNS 与系统 DNS 的边界
顶层 dns 模块为内核需要执行的域名解析提供服务器、静态映射和查询策略。它不会自动接管设备上所有 DNS 请求。只有进入内核处理路径、被路由模块要求解析,或由特定 DNS 入站交给内核的查询,才会使用这里的设置。应用自行连接外部解析服务、浏览器启用独立安全 DNS、或者请求完全绕过代理时,顶层 dns 配置可能不会参与。
这一区分对于排查非常重要。看到某个域名解析结果与配置预期不同,先确认查询由谁发起:是操作系统解析器、应用自己的解析器,还是 Xray 内置 DNS。不要同时修改系统 DNS、浏览器设置、内核服务器列表和路由规则,否则即使结果发生变化,也无法判断是哪一层起效。建议先关闭应用独立解析功能进行对照,再通过日志观察内核是否发出了查询。
{
"dns": {
"hosts": {
"domain:internal.example": "192.168.10.20",
"full:router.example": "192.168.1.1"
},
"servers": [
{
"address": "1.1.1.1",
"port": 53,
"domains": [
"geosite:geolocation-!cn"
],
"skipFallback": true
},
{
"address": "223.5.5.5",
"port": 53,
"domains": [
"geosite:cn"
],
"expectIPs": [
"geoip:cn"
]
},
"localhost"
],
"queryStrategy": "UseIP",
"disableCache": false,
"disableFallback": false,
"disableFallbackIfMatch": true
}
}
示例通过 domains 为解析服务器限定适用范围,并保留 localhost 作为后续选择。实际是否需要公共解析地址、系统解析器或其他传输形式,应根据所在网络与目标环境确定。服务器顺序、匹配域和 fallback 开关会共同影响最终选择,不能把 servers 简单理解为按顺序轮询的列表。
servers、hosts 与查询策略
servers 中既可以使用字符串形式,也可以使用对象形式。对象形式可附加端口、匹配域、期望 IP 范围和 fallback 行为。domains 用于指定哪些域名优先由该服务器处理,写法与路由域名规则类似。expectIPs 用于判断返回地址是否符合预期范围;它更接近结果筛选条件,不是把任意地址强制改成目标区域。配置不当时,正常结果可能被拒绝并触发后续查询。
hosts 提供静态域名映射,适合固定的局域网服务或明确测试目标。它不是大型 hosts 文件的替代方案,条目过多会增加维护成本。完整域名应使用 full: 限定,覆盖子域时再使用 domain:。映射到私有地址后,还应确认 routing 中的 private 规则能让连接走 direct,否则解析正确但出口选择仍可能不符合预期。
queryStrategy 控制需要哪类地址结果。常见策略包括同时允许 IPv4 与 IPv6、只使用 IPv4 或只使用 IPv6,具体名称以当前内核支持字段为准。选择只使用某一地址族前,应先确认本地网络和远端服务确实支持该路径。若本机存在 IPv6 地址但网络出口不稳定,域名可能优先返回 IPv6 后连接失败;反过来,强制 IPv4 会放弃仅提供 IPv6 的目标。稳妥做法是分别测试解析结果和实际路由,而不是只看设备是否显示某种地址。
fallback、缓存与路由闭环
fallback 机制用于在首选解析结果不满足条件或没有结果时尝试其他服务器。skipFallback 表示特定服务器不参与通用回退,disableFallback 可整体关闭回退,disableFallbackIfMatch 则用于域名已命中特定服务器时限制继续回退。多个开关叠加后容易产生“配置了服务器但从未被调用”的现象,因此应从最小配置开始:先确认单一服务器能工作,再添加域名范围和回退限制。
缓存可以减少重复查询,但会让配置修改后的结果在短时间内不立即变化。disableCache 适合短期诊断,不建议因为一次旧结果就长期关闭缓存。排查时还要考虑操作系统和应用自身缓存,它们与内核缓存相互独立。重启内核只能清理内核持有的状态,未必会清理浏览器或系统解析缓存。
DNS 与路由会形成闭环:路由可能为了匹配 IP 规则发起 DNS 查询,而 DNS 服务器本身的连接也要经过路由。若解析服务器地址是域名,又需要先解析该域名才能连接,就可能出现依赖链过长甚至循环。基础解析服务器优先使用明确地址,或保证其域名能通过系统解析器稳定获得结果。若希望 DNS 查询走特定出站,应建立清晰的标签与规则,并防止该规则再次触发同一解析路径。
典型问题是“域名规则看似正确,最终却走了错误出口”。检查顺序应为:应用提交域名还是 IP;sniffing 是否识别域名;域名规则是否先命中;domainStrategy 是否执行解析;DNS 使用了哪个服务器;返回了 IPv4、IPv6 还是两者;IP 规则是否覆盖该结果;最终出站标签是什么。把这条链条逐项记录后,问题通常能定位到一个明确环节。
| 字段 | 作用 | 适合场景 | 常见误区 |
|---|---|---|---|
| hosts | 提供静态域名映射 | 局域网服务与固定测试目标 | 误以为会改写所有应用的系统解析 |
| domains | 限定解析服务器的匹配域 | 按域名集合选择解析路径 | 忽略服务器顺序和 fallback 条件 |
| expectIPs | 筛选符合范围的解析结果 | 需要对返回地址做范围判断 | 把它当成固定地址映射 |
| queryStrategy | 控制查询使用的地址族 | 处理 IPv4 与 IPv6 路径差异 | 未测试网络能力就强制单一地址族 |
v2rayNG 与 v2flyNG 运行在 Android 网络环境中,系统的私有 DNS、应用内解析和客户端内核 DNS 也可能同时存在。判断方式与桌面端相同:先明确请求路径,再确认哪一层负责解析。不要把系统设置里的 DNS 选项与配置文件顶层 dns 字段视为同一个开关。
policy 策略:连接超时、用户等级与统计
level 策略如何关联用户
policy 用于设置连接生命周期、用户等级和系统统计行为。它不负责选择服务器,也不改变路由出口。levels 对象以等级数字作为键,每个等级可以设置握手超时、空闲超时、上下行仅剩单向活动时的连接保留时间,以及用户流量统计开关。协议用户条目中的 level 与这里的等级键关联;若用户没有显式指定,通常使用默认等级。
等级不是服务质量评分,也不会自动提供带宽优先级。它只是把一组策略参数应用到对应用户。桌面客户端作为本地单用户工具时,常见配置只需要等级 0。服务端多用户配置可能按用户分配不同等级,但本页重点是客户端运行配置:不要为了“性能优化”随意增加很多等级,先确认实际用户对象是否引用了它们。
{
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300,
"uplinkOnly": 2,
"downlinkOnly": 5,
"statsUserUplink": false,
"statsUserDownlink": false,
"bufferSize": 4
}
},
"system": {
"statsInboundUplink": false,
"statsInboundDownlink": false,
"statsOutboundUplink": false,
"statsOutboundDownlink": false
}
},
"stats": {}
}
数值单位和允许范围应以当前内核字段定义为准。示例展示常见结构,不表示所有网络都适合相同超时。过短的握手时间会让高延迟网络尚未完成连接就被终止;过长则会让失败连接占用资源更久。空闲超时也不能只按“越长越稳定”理解,长期保持大量无活动连接会增加资源消耗。
握手、空闲和单向连接超时
handshake 控制连接建立阶段允许等待的时间。远端不可达、域名解析缓慢、安全层参数不一致都可能消耗这段时间。若日志持续出现握手超时,先检查地址、端口、传输和网络可达性,而不是直接把数值调得很大。适度增加仅适用于已确认网络路径较慢、且连接最终能够成功的情况。
connIdle 控制连接在没有上下行活动时可保留多久。网页短连接通常不会依赖很长的空闲时间,但消息同步、远程终端或长轮询可能在一段时间内没有明显流量。若特定应用总在固定空闲时间后断开,可以比较应用心跳间隔与 connIdle;同时还应检查远端服务器、传输层和中间网络设备,因为任何一层都可能主动关闭连接。
uplinkOnly 与 downlinkOnly 处理只剩单向活动的情况。一个方向结束后,内核会等待另一方向完成,而不是立即关闭整个连接。数值过短可能截断尚未发送完的数据,过长则延迟资源释放。普通客户端一般沿用内核或客户端生成的合理默认值,只有日志与抓取到的连接状态明确指向单向关闭问题时才需要调整。
bufferSize 与连接缓冲有关。更大的缓冲并不必然带来更高速度,也会增加每条连接的内存使用。低性能设备、大量并发连接和大文件传输对缓冲的需求不同。优化时应一次只改变一个值,并观察内存、连接稳定性与实际吞吐的变化;不要复制面向服务端高并发环境的参数到普通桌面客户端。
统计开关与运行开销
statsUserUplink 和 statsUserDownlink 控制用户级上下行统计,system 下的字段控制入站和出站方向统计。顶层 stats 用于启用统计模块,但仅有空对象并不会自动让所有维度都产生数据,还需要对应 policy 开关以及读取统计的接口。v2rayN 界面是否展示某些统计,也取决于客户端如何启动内核和读取数据。
若不需要统计,保持相关开关关闭可以减少不必要的状态维护。若需要定位某个入站或出站是否产生流量,可以短期启用对应维度,但不能把流量变化直接等同于连接质量。统计只能说明数据经过了某个方向,不能证明域名规则、DNS 结果或远端应用响应完全正确。诊断仍需结合日志与明确测试请求。
策略模块常见误区是把连接故障归因于超时值。实际上,协议参数错误、DNS 返回不可达地址、路由选错出口、端口被占用都更常见。正确顺序是先确认结构加载、入站监听、规则命中和出站握手,再判断连接是否因生命周期策略被提前关闭。只有日志显示连接已经建立,并在某个可重复的时间点结束,policy 才是重点检查对象。
Windows、macOS、Android 与 Linux 的前台和后台网络行为不同,尤其是移动设备可能在应用进入后台后限制网络活动。这类系统级行为不能仅靠增加 connIdle 解决。若 v2rayNG 或 v2flyNG 在后台停止工作,应先检查系统对应用网络与电量使用的限制;若 v2rayN 在桌面端启动后立即退出,则应先查看端口、配置解析和内核启动日志。
policy 适合在配置已经稳定后做精细调整,而不是首次连接的必填模块。简单客户端配置可以完全依赖默认策略。只有对长连接、统计或资源使用有明确需求时,才需要加入显式 policy。字段越少,升级内核与迁移客户端时需要维护的兼容点也越少。
配置验证、日志阅读与系统化排错
先区分解析、启动与连接阶段
配置故障应先分成三个阶段。第一阶段是 JSON 解析:括号不配对、双引号缺失、尾逗号或字段类型错误会让配置无法被读取。第二阶段是内核启动:端口冲突、监听地址无效、模块字段不受支持会让进程无法正常进入运行状态。第三阶段是请求处理:服务器参数、DNS、路由、安全层或网络环境问题通常在应用发出请求后才出现。把阶段分清,可以避免在 JSON 语法错误时反复更换服务器,也能避免在远端握手失败时误查本地端口。
图形客户端里看到“启动”状态,只能说明进程可能已经运行。应继续确认本地端口是否监听、系统代理是否指向正确端口、应用是否实际发送请求,以及请求最终选择了哪个出站。v2rayN 的参数设置中可检查 Core 类型、本地 SOCKS 监听端口、局域网连接开关、sniffing、Mux、日志等级和系统代理模式。v2rayNG 与 v2flyNG 则应确认当前配置、连接模式和系统网络权限。
直接编辑 JSON 时,可以先使用本地 JSON 解析工具检查语法,但不要把包含真实服务器参数的完整配置提交到不受控的在线工具。更稳妥的方法是使用本地编辑器的 JSON 语法支持,或让内核以测试配置方式读取文件。不同内核和安装方式的命令参数可能不同,因此应以客户端实际调用方式为准,不要把其他程序的参数直接套用。
{
"log": {
"access": "",
"error": "",
"loglevel": "warning",
"dnsLog": false
}
}
warning 适合日常运行,能够保留主要异常而不过度增加输出。需要追踪规则和 DNS 时,可以短期切换到 info;完成诊断后应恢复较低输出。日志中可能包含目标域名、地址和连接时间等运行信息,分享日志前应删除与问题无关的敏感内容。不要仅截取最后一行错误,前面的解析、规则和握手信息往往更能说明原因。
按数据路径逐项定位
第一步检查入站。确认客户端显示的 SOCKS 或 HTTP 端口与应用设置一致,端口没有被其他程序占用,监听地址符合本机或局域网使用方式。可以先用一个明确支持代理设置的应用测试,避免系统代理、浏览器独立设置和应用忽略代理等因素同时出现。若应用连本地端口都无法建立连接,暂时不需要检查远端协议。
第二步检查路由输入。记录应用提交的是域名还是 IP,sniffing 是否开启,目标协议能否被识别。然后从 rules 第一条开始检查条件,不要只查看预期命中的那一条。重点寻找更靠前的宽范围规则,例如覆盖全部端口、全部网络或大型域名集合的规则。确认命中后,再核对 outboundTag 是否存在且拼写一致。
第三步检查 DNS。若域名规则已直接命中,DNS 可能只在出站连接目标时使用;若依赖 geoip 规则,则 routing 可能先解析目标。查看使用了哪个解析服务器、返回哪类地址,以及 fallback 是否改变结果。可以用完整域名和解析后的单个 IP 分别测试:域名失败而 IP 成功时,重点看 DNS 与域名规则;两者都失败时,再检查出口和网络可达性。
第四步检查出站。代理协议的地址、端口、用户参数、传输类型、安全层和服务器名称必须成组一致。若订阅导入后字段缺失,先更新订阅并确认客户端支持该分享格式。REALITY 与 XTLS Vision 等组合依赖 Xray 内核及匹配的远端参数,相关原理可参考REALITY 与 XTLS Vision 握手和流控说明。不要通过猜测逐个替换 flow、fingerprint 或 serverName,这会让原始问题失去可复现性。
第五步检查系统路径。系统代理只影响遵循该设置的应用,不能代表设备所有连接都经过本地入站。若某个应用正常、另一个应用直连,先确认后者是否支持系统代理。Windows、macOS 和 Linux 的代理设置入口不同,Android 客户端则通常通过系统提供的网络连接能力接管流量。平台安装与客户端选择可参考客户端对比。
| 现象 | 优先检查 | 下一步 |
|---|---|---|
| 内核无法启动 | JSON 语法、字段支持、端口占用 | 恢复最小配置,再逐段加入模块 |
| 应用无法连接本地代理 | 监听地址、端口、应用代理类型 | 确认 SOCKS 与 HTTP 设置没有混用 |
| 部分域名出口错误 | 规则顺序、sniffing、domainStrategy | 查看域名与 IP 两种输入的命中差异 |
| 域名失败但 IP 可连接 | DNS 服务器、hosts、地址族 | 检查 fallback 与应用独立解析 |
| 连接建立后固定时间断开 | connIdle、单向超时、系统后台限制 | 对照日志中的建立与关闭时间 |
最小配置与二分恢复法
当配置经过多次修改后无法判断是哪一段出错,最有效的方法是恢复最小配置。保留一个本地 SOCKS 入站、一个已知参数完整的代理出站、direct 出站和一条简单兜底规则,暂时移除自定义 DNS、复杂路由、统计和策略。如果最小配置能够工作,再按模块逐次恢复,每次只加入一组相关字段并完成固定测试。
规则很多时可以使用二分法:先停用一半自定义规则测试,如果问题消失,故障位于被停用部分;如果仍存在,则位于保留部分或其他模块。继续缩小范围,通常比逐条随机移动更快。DNS 服务器列表和 hosts 映射也可以使用同样方法。每轮测试应保持服务器、应用、目标域名和网络环境不变,否则测试结果不可比较。
建议为稳定配置保留一份结构化记录,包括客户端类型、Core 类型、入站端口、出站标签、路由规则目的、DNS 选择理由和调整过的 policy 字段。记录理由比只保存配置更重要,因为数据集合、网络环境和客户端生成逻辑变化后,旧规则未必仍适用。定期删除已经无法说明用途的例外规则,避免配置逐渐变成只敢增加、不敢修改的状态。
图形客户端更新订阅或切换内核后,应重新检查自定义字段是否仍被写入最终运行配置。v2rayN 的 Avalonia 桌面版与 Windows WPF 版在界面和平台支持上存在差异,但核心排查路径一致,具体选择可参阅v2rayN 桌面版与 WPF 版区别。macOS 首次启动或网络权限异常时,可查看macOS 安装与网络权限处理步骤。
如果错误信息仍无法归类,可前往疑难解答按基础认知、安装配置、使用技巧和故障排查分类继续定位。提问或记录问题时,应包含可复现步骤、客户端名称、操作系统、内核类型、相关配置片段和经过处理的日志,而不是只描述“无法使用”。信息越接近实际数据路径,越容易判断故障属于入站、路由、DNS、出站还是系统网络层。
配置文件的目标不是堆叠最多字段,而是让每条连接的处理过程可预测。先使用客户端生成的默认结构建立可工作的基线,再根据明确需求增加路由、DNS 和策略;每项修改都保留测试场景与恢复路径。这样既能使用 v2rayN、v2rayNG 或 v2flyNG 的图形管理能力,也能在出现问题时直接阅读运行配置并定位到具体模块。