ssl_prefer_server_ciphers on 是将 tls 握手加密套件选择权交还服务器的关键开关,但必须与严格排序的 ssl_ciphers(如 ecdhe+aes-gcm/chacha20)、禁用 tlsv1.0/1.1、指定安全 ecdh 曲线及 server 块内实测验证协同生效。

开启 ssl_prefer_server_ciphers on 是把 TLS 握手时加密套件的选择权从客户端交还给服务器的关键一步,但它本身不决定强弱——真正起作用的是你如何搭配 ssl_ciphers、协议限制和密钥交换参数,并确保它们在实际连接中生效。
必须与 ssl_ciphers 显式配合使用
单独写 ssl_prefer_server_ciphers on; 没有效果。它只是“执行开关”,而加密套件的实际内容、优先级和安全性全靠 ssl_ciphers 定义:
- 推荐直接用明确、现代、支持前向保密(PFS)的套件列表,例如:
ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305 - 禁用已淘汰算法:在套件末尾加
!RC4:!MD5:!SHA1:!DES:!3DES:!EXPORT:!aNULL:!eNULL等后缀强化过滤 - 避免模糊表达如
HIGH或!aNULL:!MD5,它们无法排除非 PFS 套件或 SHA1 签名组合
限定协议版本并同步收紧密钥交换
TLS 版本控制和加密套件控制是两道独立防线。即使套件再强,若允许老旧协议或弱密钥交换,仍可能协商出不安全连接:
- 强制启用 TLSv1.2 和 TLSv1.3:
ssl_protocols TLSv1.2 TLSv1.3;
不要写TLSv1或TLSv1.1,它们等价于 TLSv1.0,已被主流浏览器弃用且存在已知漏洞 - 指定高效安全曲线:
ssl_ecdh_curve secp384r1:prime256v1;
secp384r1 运算更快、安全性更高;prime256v1 兼容性更广,能覆盖部分老旧 Android 或嵌入式设备 - 可选增强:
ssl_dhparam /path/to/dhparam.pem;(建议使用 2048 位以上 DH 参数)
配置位置必须准确,避免继承失效
这个参数虽小,但放错位置或漏验证等于白配:
- 建议统一写在
server块内,和ssl_certificate、ssl_ciphers等其他 SSL 参数保持一致 - 避免只在
http块全局开启,却在某个server中漏配ssl_ciphers,这会导致该站点回退到 Nginx 默认弱套件 - 反代服务常有多个
server块(如 HTTP 跳转、HTTPS 主站、API 子路径),ssl_prefer_server_ciphers必须明确写在承载 HTTPS 的那个server块内,不能只靠全局设置 - 该指令不支持
location级别作用域,避免在location块里重复或覆盖
验证是否真正生效,不能只 reload 就算完
改完配置后务必实测确认协商结果:
- 先运行
nginx -t检查语法,再nginx -s reload重载 - 用 OpenSSL 验证 TLSv1.2 协商:
openssl s_client -connect yourdomain.com:443 -tls1_2 | grep "Cipher is"
输出应是你ssl_ciphers列表中最靠前的那个强套件 - 用 SSL Labs 的 SSL Server Test 全面扫描,重点看 “Handshake Simulation” 中各客户端是否都协商到
ECDHE+GCM/ChaCha20,“Key Exchange” 是否显示 PFS,目标评级 A+ - 检查 Nginx 错误日志,确认无 SSL 相关警告或 fallback 提示











