多层反向代理导致TLS协议降级故障排查
认识问题:你遇到的其实不是“代理自动降级”
当你给网站套了两层甚至三层 反向代理(比如客户端→Nginx A→Nginx B→后端服务器),有时会发现浏览器访问时只支持TLS 1.2,明明源站支持TLS 1.3。
这并非协议“自动降级”了,而是每层代理在和下一层建立连接时,使用了自己默认的SSL协议栈。
如果中间代理的 ssl_protocols 或 proxy_ssl_protocols 没有明确写明高版本,就会悄悄降低安全级别。
本文带你系统排查并修复这个“隐形坑”。
环境检查:先确认你用的代理软件和版本
动手前,先登录每台代理服务器,执行下面命令确认当前版本:
nginx -v 2>&1 | grep -o 'nginx/[0-9.]*'
输出类似 nginx/1.24.0。
不同版本对TLS 1.3的支持起始于 1.13.0(OpenSSL 1.1.1以上)。
如果你的版本太低,请先升级。
同时记录下每层代理的 nginx.conf 路径,通常是 /etc/nginx/nginx.conf 或 /etc/nginx/conf.d/ 下。
操作步骤:逐层抓出“谁在拖后腿”
第一步:检查每层代理本身的SSL配置
在每台代理上执行以下命令,查看当前Nginx编译时使用的SSL库:
nginx -V 2>&1 | grep -i ssl
如果你看到 TLSv1.3 字样,说明编译支持。
接着查看 ssl_protocols 配置(通常位于 server 块或 http 块):
grep -r 'ssl_protocols' /etc/nginx/
常见的错误是设为 TLSv1 TLSv1.1 TLSv1.2,没有包含 TLSv1.3。
应改为:
ssl_protocols TLSv1.2 TLSv1.3;
(不推荐包含 TLSv1 和 TLSv1.1,因为它们已不安全。
)
第二步:重点检查代理到后端的连接(proxy_pass)
这是最容易被忽略的环节。
当Nginx使用 proxy_pass 转发请求时,自己会作为客户端与后端建立SSL连接。这个连接的协议版本由 proxy_ssl_protocols 控制,而不是 ssl_protocols!
找到配置中类似这样的位置:
location / {
proxy_pass https://upstream-backend;
}
在 server 块或 location 块内部添加:
proxy_ssl_protocols TLSv1.2 TLSv1.3;
proxy_ssl_ciphers HIGH:!aNULL:!MD5;
proxy_ssl_protocols 默认值在 Nginx 1.17.4 之前是 TLSv1 TLSv1.1 TLSv1.2,之后是 TLSv1.1 TLSv1.2 TLSv1.3。
如果你用的版本低于 1.17.4,必须手动指定。
第三步:调整后端服务器的SSL配置(如果后端也是Nginx)
如果你还会把请求转发到另一台Nginx(比如负载均衡),那台“后端Nginx”也要确认 ssl_protocols 包含 TLSv1.3。
避坑指南:这些细节会让你白忙一场
- proxy_ssl_* 参数只影响代理到后端的连接,不影响客户端到代理的连接。两边需要分别配置。
- 如果你用了
upstream块(如upstream backend { server 10.0.0.1:443; }),proxy_ssl_protocols需要放在server或location内,upstream 块本身不支持SSL参数。 - 修改配置后,一定要 reload 而不是 restart:
nginx -s reload。否则正在处理的连接会中断。 - 如果你用宝塔面板,请在“网站设置→SSL→SSL协议版本”中选择“TLSv1.2 TLSv1.3”,同时检查“反向代理”配置中的“代理SSL协议”。
验证方法:用 openssl 逐级确认
修改完成后,分两步验证:
- 验证客户端到第一层代理:从外网用 openssl 测试:
echo | openssl s_client -connect 你的域名:443 -tls1_3 2>/dev/null | grep 'New, TLSv1.3'
如果输出 New, TLSv1.3 说明客户端到代理是TLS 1.3。
- 验证代理到后端连接:在内网代理服务器上测试:
echo | openssl s_client -connect 后端IP:后端端口 -tls1_3 2>/dev/null | grep 'New, TLSv1.3'
如果这一步失败,重点检查代理服务器的 proxy_ssl_protocols。
还可以给每层代理的 access log 加上 $ssl_protocol 变量,查看实际握手版本。
在 log_format 中添加:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$ssl_protocol"';
然后查看日志,就能清楚看到每个请求使用的TLS版本。
写在最后
多层反向代理导致TLS协议降级的罪魁祸首往往是 proxy_ssl_protocols 默认值太低,或者某层代理的编译版本不支持TLS 1.3。
按本文步骤逐一排查,重点检查每一层与下一层连接的SSL配置,并确保所有Nginx版本≥1.13.0且编译了OpenSSL 1.1.1以上。
配置修改后通过 openssl 和日志双重验证,就能彻底解决问题。
如果你在排查中遇到其他异常,欢迎在评论区留言交流。