nginx只能基于实际协商成功的tls版本(如tlsv1.2/tlsv1.3)做条件路由,通过$ssl_protocol变量配合map实现;该变量需https启用、nginx≥1.15.0、openssl≥1.1.1才可用,无法在握手前识别客户端支持的版本列表。

不能直接按客户端“支持”的 TLS 版本分流,只能按实际协商成功的 TLS 版本做条件路由。Nginx 无法在连接建立前预知客户端支持哪些版本,它只能在 SSL 握手完成后,通过 $ssl_protocol 变量拿到最终选定的协议(如 TLSv1.2 或 TLSv1.3),再据此做后续处理。
前提:确保 $ssl_protocol 可用
该变量不是默认始终可用,需满足以下条件:
- server 块监听端口启用
ssl,例如listen 443 ssl http2; - 已配置有效的
ssl_certificate和ssl_certificate_key - Nginx ≥ 1.15.0(推荐),OpenSSL ≥ 1.1.1(否则不支持 TLSv1.3)
- HTTP 请求必须走 HTTPS 连接;纯 HTTP 请求中
$ssl_protocol为空或未定义
用 map 构建协议版本标识
在 http 块中定义映射,把原始协议名转为易读、易判断的值:
map $ssl_protocol $tls_route {
default "legacy";
TLSv1.2 "v12";
TLSv1.3 "v13";
}
注意:map 是精确字符串匹配,大小写和拼写必须与 Nginx 实际输出完全一致(如不能写成 tlsv1.2 或 TLS 1.2)。
在 server 或 location 中做条件路由
有了 $tls_route,就可以用于 upstream 选择、响应头注入、跳转或内容替换:
- 分发到不同后端:
proxy_pass http://backend_$tls_route; - 返回协议提示页:
if ($tls_route = "legacy") { return 302 /tls-deprecation-notice.html; } - 注入调试头:
add_header X-TLS-Routed $tls_route; - 结合 Cookie 实现稳定灰度:
map $cookie_tls_test $upstream_group { ~v13 "v13-cluster"; default "default-cluster"; },再与$tls_route联合判断
重要限制与替代思路
以下情况 Nginx 本身无法做到:
- 根据 ClientHello 中声明的“支持版本列表”分流(那是握手前信息,Nginx 不解析 ClientHello)
- 在 stream 模块中使用
$ssl_protocol(它只存在于 http 模块上下文) - 用
split_clients基于 TLS 版本做 A/B 测试(该指令执行早于 SSL 解密,$ssl_protocol尚不可用)
若需更前置的识别,可考虑用 stream_ssl_preread 模块读取 SNI,或引入外部 TLS 解析代理提取 JA3/JA4 等指纹——但这些已超出 Nginx 原生命令能力范围。











