1. 问题背景与现象
在单台服务器上使用 Nginx 部署多个站点,并通过 Cloudflare(开启小黄云代理)进行 CDN 加速与安全防护。
初始状态:服务器上仅运行站点
markdown.18401949.xyz,配置如下:1 2 3 4 5 6server { listen 443 ssl; http2 on; # 使用了 Nginx 1.25.1+ 的新版写法 server_name markdown.18401949.xyz; # ... SSL 证书及反代配置 }此时站点访问完全正常。
异常现象:当新增第二个站点
claw.oopses.de,并使用 Certbot 默认生成的旧版 HTTP/2 写法后:1 2 3 4 5server { listen 443 ssl http2; # 使用了旧版的混合写法 server_name claw.oopses.de; # ... SSL 证书及反代配置 }故障表现:保存并重载 Nginx 后,原本正常的
markdown站点立刻无法访问,Cloudflare 直接抛出 525 SSL Handshake Failed 错误。抓包分析显示,Cloudflare 尝试访问markdown时,Nginx 错误地返回了claw的 SSL 证书,导致域名不匹配,握手被强制断开。
2. 原因详细分析
导致这一诡异现象的根本原因,在于 Nginx 在 1.25.1 版本前后对 HTTP/2 指令的设计变更,以及旧版指令在多虚拟主机(Virtual Host)环境下的“全局污染”特性。
2.1 Nginx 官方对 HTTP/2 指令的废弃与调整
在 Nginx 1.25.1(2023年6月发布)及后续版本中,官方重构了 HTTP/2 配置架构:
- 旧版写法(已废弃):
listen 443 ssl http2; - 新版写法(推荐):
listen 443 ssl; http2 on;
2.2 旧版 listen ... http2 的全局污染机制
SSL 握手发生在应用层协议(HTTP/2)协商之前。旧版指令具有端口级别的全局侵入性,导致 Nginx 内部状态机发生冲突:
- SNI 协商干预:在标准 HTTPS 握手中,客户端通过 SNI 告知目标域名,Nginx 匹配
server_name并提供正确证书。 - 配置上下文飘移:当
listen 443 ssl http2;存在时,Nginx 在高并发下倾向于在完成 SNI 匹配前,提前应用第一个加载的 HTTP/2 SSL 上下文缓存。 - Cloudflare 回源触发冲突:Cloudflare 节点回源采用高并发连接池。Nginx 内部因新旧状态机冲突,错误地将先加载的
claw证书返回。Cloudflare 检测到回源证书域名与请求域名不匹配,安全机制触发,直接中断握手并抛出 525 错误。
3. 解决办法
核心逻辑:彻底淘汰旧版写法,将全站 Nginx 配置指令集对齐。
3.1 修改 claw.oopses.de 配置
将 listen 后面的 http2 关键字移除,改为独立指令:
| |