Xray v26.7.11 更新后 REALITY authentication failed 排障记录
前言
最近我在复用一套 Vultr 自动化部署脚本重建 Xray 服务时,遇到了一个有些反直觉的问题:Clash 规则和 Xray 基础配置都没有变化,节点却在一次重新部署后持续报 REALITY authentication failed。
看到“认证失败”,第一反应通常是检查 UUID、Reality 公私钥、Short ID 和 SNI。我也按这个思路逐项核对,但客户端与服务端的参数完全一致,端口和网络也都正常。继续对比运行环境后才发现,真正变化的是部署时重新拉取的 teddysun/xray:latest 镜像,以及镜像内 Xray-core 的默认行为。
这篇文章记录完整的定位过程,也说明为什么一份已经验证过的配置,会在重新拉取镜像后得到不同结果。
结论先行
这次故障不是 Clash 节点参数或 Xray 基础配置写错,而是上游默认行为变化经由可变的 Docker latest 标签进入自动化部署后造成的客户端兼容性问题。
服务端升级到 Xray-core v26.7.11 后,如果 REALITY 配置没有显式填写 minClientVer,Xray 会把最低客户端版本默认设为 26.3.27。与此同时,Mihomo v1.19.25/v1.19.28 在 REALITY ClientHello 中仍声明版本 1.8.2,于是握手在进入 VLESS 层之前就被服务端拒绝,客户端统一报错:
1 | REALITY authentication failed |
已经实际验证两种修复方式都有效:
- 将 Xray-core 回退并固定为
v26.6.27; - 保持 Xray-core
v26.7.11,在服务端realitySettings中显式添加:
1 | "minClientVer": "1.8.2" |
环境与背景
我的服务端通过 Docker Compose 部署在 Vultr VPS 上,镜像使用 teddysun/xray。部署本身由自编写的 Vultr 自动化脚本完成,因此在创建新服务器或重构服务时会重新拉取镜像。
服务器环境:
- 操作系统:Ubuntu
22.04.5 LTS(Jammy Jellyfish) - Linux kernel
5.15.0-185-generic - 架构:
x86_64/linux/amd64 - Docker Engine
29.1.3,API1.52 - Docker Compose
2.40.3 - containerd
2.2.1 - runc
1.3.4
客户端环境:
- Clash Verge Rev
v2.5.1 - Mihomo
v1.19.25 - VLESS + TCP + REALITY + Vision
flow: xtls-rprx-vision
服务端故障版本:
1 | Xray 26.7.11 (Xray, Penetrates Everything.) 50231ea |
同一套脚本和配置在镜像更新前能够正常工作,重新部署并拉取新镜像后节点却全部失联。这种“配置没变,部署结果变了”的特征,最终成为定位镜像漂移的关键线索。
故障现象
Clash 日志持续出现:
1 | [TCP] dial GLOBAL 198.18.0.1:58911 --> accounts.example.com:443 |
偶尔还会混有:
1 | context deadline exceeded |
服务端则表现为:
access.log中没有任何 VLESS 入站记录;error.log只有Xray 26.7.11 started;- 端口、域名解析和 TCP 连通性正常。
这里有两个容易误判的点:
198.18.0.1是 Clash/Mihomo Fake-IP 地址,不是服务端地址,也不是故障原因;access.log为空并不表示连接没有到达服务器。REALITY 在 VLESS 用户认证之前就拒绝了握手,因此请求不会进入 VLESS access log。
先排除配置错误
客户端和服务端逐项核对后,以下内容全部一致:
| 项目 | Clash/Mihomo | Xray 服务端 | 结果 |
|---|---|---|---|
| 协议 | vless |
vless |
一致 |
| 端口 | 2223 |
2223 |
一致 |
| 传输层 | tcp |
tcp |
一致 |
| Flow | xtls-rprx-vision |
xtls-rprx-vision |
一致 |
| SNI | www.apple.com |
serverNames: [www.apple.com] |
一致 |
| Reality 目标 | 客户端无需配置 | www.apple.com:443 |
正常 |
| UUID | 已逐字符验证 | 已逐字符验证 | 一致 |
| Short ID | 偶数长度十六进制 | 同一原值 | 一致 |
| Reality 密钥 | 客户端公钥 | 服务端私钥推导所得公钥 | 配套 |
这一步很重要:REALITY authentication failed 最常见的确是公钥、Short ID、SNI 或 UUID 不一致,但本次并不是这些原因。
版本变化与故障时间线
| 时间(香港时间) | 事件 |
|---|---|
| 镜像更新前 | 自动化部署拉取旧版 teddysun/xray:latest,节点正常 |
| 2026-07-11 22:30 左右 | Xray-core 提交新的 REALITY 默认最低客户端版本逻辑 |
| 镜像更新后 | teddysun/xray:latest 指向包含 Xray-core v26.7.11 的新镜像 |
| 再次部署时 | 自动化脚本重新拉取镜像,相同配置开始报认证失败 |
| 2026-07-13 | 完成参数核对、版本对比,并验证回退版本与显式设置 minClientVer 均可恢复 |
Docker Hub 页面显示 teddysun/xray:latest 在故障前后发生了更新(截图时间为 2026-07-13 13:00):

Compose 文件中的 image: teddysun/xray 等价于使用 teddysun/xray:latest。latest 是一个可以移动的标签,并不代表固定构建。因此 Compose 文件虽然没变,重新拉取时得到的镜像 digest 和 Xray 版本仍可能不同。
还需要注意,标签移动不会自动替换已经运行的容器。真正把新版本带进环境的是新建 VPS、重新执行自动化部署、docker compose pull,或其他会重新拉取并创建容器的流程。
根本原因:minClientVer 的默认值发生变化
Xray-core 在 2026-07-11 的提交 af7eb680 中加入了以下逻辑:
1 | } else { |
也就是说,从包含该提交的 Xray-core v26.7.11 开始,即使服务端配置文件没有填写 minClientVer,也不再表示“不限制客户端版本”,而是自动得到:
1 | "minClientVer": "26.3.27" |

截图右侧的 v26.3.27 · Mar 28 容易造成时间线误读(截图时间为 2026-07-13 13:00)。3 月 28 日发布的是被选作最低版本基线的 26.3.27;真正改变默认行为的提交发生在 7 月 11 日,并进入了 v26.7.11。 因此这不是一个从 3 月持续潜伏到 7 月的配置错误,而是 7 月的新默认值通过镜像更新进入了部署环境。
另一方面,Mihomo 当时在 REALITY ClientHello 的 Session ID 中仍硬编码:
1 | hello.SessionId[0] = 1 |
服务端将其解释为客户端版本 1.8.2。最终比较结果是:
1 | Mihomo 声明版本:1.8.2 |
所以 REALITY 握手必然被拒绝,且错误发生在 VLESS 用户认证之前。
相关 issues
最初找到的是 XTLS/Xray-core #6482,创建于 2026-07-12 14:38 UTC,描述的是 XHTTP + REALITY 从 v26.6.27 升级到 v26.7.11 后失效。维护者在回复中直接指向上述提交,并建议通过 minClientVer 调整兼容范围。
更早、也与本次协议组合更一致的是:
- XTLS/Xray-core #6477:创建于 2026-07-12 03:29 UTC,明确复现 Mihomo + VLESS + TCP/raw + REALITY + Vision 在
v26.7.11上统一报authentication failed;回退到v26.6.27后恢复。 - MetaCubeX/mihomo #2967:创建于 2026-07-12 04:38 UTC,进一步指出 Mihomo 将 REALITY 客户端版本硬编码为
1.8.2,而 Xray 新默认下限为26.3.27。
因此,#6482 是同一版本门槛问题在 XHTTP + REALITY 上的表现;本次 VLESS + TCP + REALITY + Vision 最直接对应的是更早的 #6477。
修复方案一:回退并固定 Xray 为 26.6.27 版本
这是最适合快速恢复和做单变量验证的方案:不修改任何节点参数,只改变 Xray 版本。
1 | services: |
应用镜像:
1 | docker compose pull xray |
修改 Compose 文件后,可以先运行 docker compose config -q 检查 YAML。更换镜像时不能只执行 docker compose restart:restart 只会重启原容器,不会应用新的镜像版本。
确认输出包含:
1 | Xray 26.6.27 |
本次实际验证:回退后,无需修改 Clash 和 Xray 基础配置,REALITY 节点立即恢复。
修复方案二:保留 Xray 26.7.11,显式兼容 Mihomo
在服务端 realitySettings 中加入:
1 | "minClientVer": "1.8.2" |
完整结构示例:
1 | "realitySettings": { |
重启服务:
1 | docker compose restart xray |
本次实际验证:Xray 保持 v26.7.11 时,加入 minClientVer: "1.8.2" 同样能够恢复连接。
这里填写 1.8.2,是因为 Mihomo 在 REALITY ClientHello 中实际声明的版本就是 1.8.2。minClientVer 表示服务端允许接入的最低客户端版本,因此设置为 1.8.2 已经足够兼容当前 Mihomo。
Issue 中提到的 1.0.0 也能生效,是因为 1.8.2 高于 1.0.0,但它会允许更低版本的客户端接入,放宽范围比实际需要更大。需要强调的是,1.8.2 和 1.0.0 都是在主动覆盖 Xray v26.7.11 新增的默认版本限制,只适合作为临时兼容方案,不建议长期使用。更稳妥的做法仍然是等待或更换兼容新版本校验的客户端;在此之前,也可以固定已验证可用的 Xray 版本。
给自动化部署脚本的改进
这次问题最有价值的结论并不是“不要升级”,而是让升级变得可观察、可验证、可回滚。
1. 不在生产部署中使用裸 latest
至少固定版本标签:
1 | image: teddysun/xray:26.6.27 |
对可重复性要求更高时,可进一步固定镜像 digest。
2. 部署完成后记录真实版本
1 | docker exec xray xray version |
自动化日志应保存这三项,避免只知道“部署成功”,却不知道实际运行了哪个构建。
3. 加入协议级健康检查
仅检查容器 running 或端口可连接是不够的。这次故障中 TCP 端口完全正常,失败发生在 REALITY 握手阶段。部署完成后应实际通过目标节点发起一次代理请求,并验证出口或目标响应。
4. 保留上一版本的快速回滚入口
将镜像版本做成脚本变量,例如:
1 | XRAY_IMAGE=teddysun/xray:26.6.27 |
新版本验证失败时只需恢复变量并重构服务,而不必临时修改多处 Compose 内容。
5. 升级时先对比运行版本,而不是首先怀疑密钥
这次最初看到 REALITY authentication failed,自然会优先怀疑 UUID、公钥、Short ID 和 SNI。但当“相同配置此前正常、重新部署后突然失败”时,应该尽早加入以下检查:
1 | docker exec xray xray version |
版本漂移往往比配置漂移更隐蔽。
最终结论
本次故障链路可以概括为:
1 | 自动化重新部署 |
镜像更新前的成功部署已经说明基础配置本身可用。真正变化的是镜像中 Xray-core 的版本,以及新版本在未显式设置 minClientVer 时采用的默认行为。
最终,两条路径都已验证有效:
- 回退并固定
teddysun/xray:26.6.27; - 保留 Xray
v26.7.11,显式设置"minClientVer": "1.8.2"。
对于继续使用 Mihomo 客户端的环境,第二种方案允许继续升级 Xray;对于强调默认安全策略、不希望放宽客户端版本门槛的环境,可以先固定 v26.6.27,再根据后续生态兼容情况决定升级策略。