应分场景按设备能力配置tls策略:通过$ssl_protocol与ua联合统计识别真实客户端,为旧设备设独立子域名及兼容server块,同步调整后端proxy_ssl配置,并渐进淘汰低版本tls。

旧版客户端(如 Android 4.4、iOS 9 早期版本、部分 WebView 或 JDK 6/7 应用)不支持 TLSv1.3,直接启用会导致连接中断、握手失败或静默断连。这不是配置写错了,而是协议能力不匹配——必须分层识别、隔离适配,不能“一刀切”降级整个站点。
先确认哪些请求实际卡在 TLSv1.3
别只看 User-Agent,它常不可靠。真实协议版本由 Nginx 握手后记录为 $ssl_protocol 变量:
- 在 access_log 中加入该字段:log_format main ... "$ssl_protocol";
- 统计近期低版本协议请求:zcat access.log* | awk '$12 ~ /TLSv1[.][01]/ {print $11}' | sort | uniq -c
- 重点查出现 TLSv1.0 或 TLSv1.1 的 UA,它们大概率无法协商 TLSv1.3,强行启用就会失败
用子域名隔离旧设备流量
把兼容性问题从“全局降级”变成“定向适配”,避免影响现代客户端:
- 为旧设备单独配置 server 块,例如绑定 legacy.example.com
- 其中明确限定协议和套件:ssl_protocols TLSv1.1 TLSv1.2;
- 套件保留向后兼容项:ssl_ciphers 'ECDHE-RSA-AES128-SHA:AES128-SHA:ECDHE-ECDSA-AES128-GCM-SHA256';
- 禁用 HTTP/2:http2 off;(旧 WebView 不支持 ALPN,会降级失败)
后端代理也需同步降级
Nginx 前端兼容了,但若后端(如 Spring Boot + Tomcat 8.0、Java 7 应用)只支持 TLSv1.1,Nginx 默认用 TLSv1.2 去连,API 就会批量 502:
- 在对应 location 或 upstream 中设置:proxy_ssl_protocols TLSv1.1;
- 配套指定兼容套件:proxy_ssl_ciphers "ECDHE-RSA-AES128-SHA:AES128-SHA";
- 务必开启 SNI:proxy_ssl_server_name on;(多证书环境必需)
- 实测验证:openssl s_client -connect backend:8443 -tls1_1 -servername example.com
验证是否真因 TLSv1.3 被拒
用 OpenSSL 主动探测,绕过浏览器干扰:
- 强制测试 TLSv1.3:openssl s_client -connect example.com:443 -tls1_3 -servername example.com 2>/dev/null | grep "Protocol" → 若无输出或显示 TLSv1.2,说明被拒绝
- 对比 TLSv1.2:openssl s_client -connect example.com:443 -tls1_2 -servername example.com 2>/dev/null | grep "Protocol" → 若成功,基本锁定是 TLSv1.3 兼容问题
- 注意:结果取决于 OpenSSL 运行时版本 —— 系统自带 OpenSSL 1.0.2k(如 CentOS 7)根本不支持 TLSv1.3,即使 Nginx 配置了也无效











