Nginx配置HTTPS + HTTP/2的全过程及避坑指南
给站点配好 HTTPS,浏览器地址栏出现小锁头,很多人就以为搞定了。但拿去 SSL Labs(ssllabs.com/ssltest)一测,评分可能只有 B——证书链不全导致部分客户端报错、支持了早已被攻破的 TLS 1.0、握手慢得肉眼可见。这篇按「先能用、再安全、后提速」的顺序,把一份 Nginx HTTPS 配置从「有锁头」调到 SSL Labs A+,每一项都讲清楚为什么。
最小可用版:先让 HTTPS 跑起来
假设证书已经签好(Let’s Encrypt 或商业 CA),最小配置长这样:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
location / {
root /var/www/html;
}
}nginx -t 通过、nginx -s reload,浏览器能打开 https 了。但这份配置有一堆问题:HTTP 还能访问、可能用了不全的证书链、默认协议里带着 TLS 1.0/1.1。下面逐个修。
坑一:证书链不全,部分设备报「不受信任」
最隐蔽的坑是证书链缺中间证书。你在自己浏览器打开好好的,但某些安卓机、Java 客户端、curl 却报 unable to verify the first certificate。因为浏览器会缓存或自动补全中间证书,而很多客户端不会——它们需要你在服务端就把完整链发下去。
关键点:ssl_certificate 指向的文件必须是「站点证书 + 中间证书」拼在一起的全链文件(顺序是站点证书在前、中间证书在后),不是只有站点证书那一张。
# Let's Encrypt 的 fullchain.pem 已经是全链,直接用它 # 商业 CA 通常给你 your_domain.crt 和 intermediate.crt 两个文件,需手动拼: cat your_domain.crt intermediate.crt > /etc/nginx/ssl/example.com.crt
# 指向全链文件,不是单张站点证书 ssl_certificate /etc/nginx/ssl/example.com.crt; # fullchain ssl_certificate_key /etc/nginx/ssl/example.com.key;
验证链是否完整,用 openssl 连一下看 Verify return code:
# 加 -servername 触发 SNI,否则多站点服务器可能返回错证书 echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \ | grep -i "verify" # 期望看到 "Verify return code: 0 (ok)"
Verify return code: 0 (ok) 才算链完整。如果是 21 (unable to verify...),就是中间证书没拼上。
坑二:开 HTTP/2 提速,但语法有讲究
HTTP/2 能多路复用、头部压缩,同一域名大量小资源的站点提速明显。老写法是 listen 443 ssl http2;,但从 Nginx 1.25.1 起推荐用独立的 http2 指令(写在 listen 后面那种在新版会告警):
server {
listen 443 ssl;
http2 on; # Nginx 1.25.1+ 推荐写法
server_name example.com;
# ...
}如果你的 Nginx 是 1.25 之前的版本,还得用 listen 443 ssl http2;。用 nginx -v 看版本决定写哪种。注意 HTTP/2 强依赖 HTTPS——浏览器只在 TLS 上启用 HTTP/2,所以它必须和 ssl 一起配。
坑三:协议和加密套件——砍掉不安全的,才能上 A
SSL Labs 给 A 以下评分,十有八九是因为还开着 TLS 1.0/1.1(已被 PCI DSS 淘汰)或弱加密套件。安全基线配置:
# 只留 TLS 1.2 和 1.3,砍掉 1.0/1.1 ssl_protocols TLSv1.2 TLSv1.3; # 加密套件:优先前向保密(ECDHE)的强套件 ssl_ciphers 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; # TLS 1.3 的套件由客户端优选更优,1.2 场景保留服务端优先 ssl_prefer_server_ciphers off; # 复用握手结果,减少重复握手开销 ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; # 关掉 session ticket,避免前向保密被削弱
几个要点:ssl_protocols 去掉 1.0/1.1 是上 A 的硬门槛;ECDHE 开头的套件提供前向保密(即使私钥泄露,历史流量也解不开),这是 A+ 必备;ssl_session_cache 让重复访问的客户端跳过完整握手,直接提速。
坑四:OCSP stapling——把「查证书吊销」的延迟省掉
浏览器为了确认你的证书没被吊销,默认要自己去 CA 的 OCSP 服务器查一次,这一步既慢又泄露用户访问了哪个站。OCSP stapling 让 Nginx 代替浏览器提前查好,握手时直接把「证书有效」的凭证一起发下去,省掉浏览器那次外网请求:
ssl_stapling on; ssl_stapling_verify on; # 验证 stapling 响应需要 CA 的根+中间证书链 ssl_trusted_certificate /etc/nginx/ssl/ca-chain.pem; # Nginx 要能解析 OCSP 服务器域名,配个 DNS resolver 223.5.5.5 8.8.8.8 valid=300s; resolver_timeout 5s;
验证 stapling 是否生效:
echo | openssl s_client -connect example.com:443 -servername example.com -status 2>/dev/null \ | grep -A 3 "OCSP Response Status" # 生效会看到 "OCSP Response Status: successful"
注意 ssl_stapling_verify on 需要 ssl_trusted_certificate 指向包含根证书+中间证书的链文件(和站点证书那个 fullchain 不完全一样,这个要带根)。漏了 resolver,Nginx 解析不了 OCSP 域名,stapling 会静默失败。
坑五:HSTS——强制浏览器只走 HTTPS
即使你把 HTTP 跳转到了 HTTPS,用户第一次输 http:// 的那一跳仍是明文,存在中间人降级攻击的窗口。HSTS 让浏览器记住「这个站以后一律用 HTTPS」,连第一跳都省了:
# max-age 一年;includeSubDomains 覆盖子域;preload 可申请进浏览器预置名单 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
always 参数很关键——不加的话,4xx/5xx 错误响应里不会带这个头。上 HSTS 前务必确认所有子域都已支持 HTTPS,否则 includeSubDomains 会把没配证书的子域也锁死成只能 HTTPS,直接打不开。这是不可逆的坑,先小范围 max-age 测试再拉长。
补齐:HTTP 强制跳 HTTPS
最后把 80 端口的明文请求 301 到 HTTPS,别让用户有机会走明文:
server {
listen 80;
server_name example.com;
# 全部 301 到 https,HSTS 才有意义
return 301 https://$host$request_uri;
}改完 nginx -t 确认语法、nginx -s reload 生效,再去 SSL Labs 重测,证书链、协议、前向保密、HSTS、OCSP 全绿就能拿到 A+。
小结
ssl_certificate必须指向全链文件(站点证书+中间证书),否则部分客户端报「证书不受信任」;用openssl s_client看Verify return code: 0验证。- HTTP/2 强依赖 HTTPS,Nginx 1.25.1+ 用独立的
http2 on;,老版本用listen ... http2。 - 上 A 的硬门槛:
ssl_protocols只留 TLS 1.2/1.3,加密套件用 ECDHE 开头的前向保密套件。 - OCSP stapling 让 Nginx 代查证书吊销状态,省掉浏览器外网请求;记得配
resolver和带根证书的ssl_trusted_certificate。 - HSTS 强制 HTTPS,但
includeSubDomains不可逆,上线前确认所有子域都支持 HTTPS,先短 max-age 试。 - 一句话记忆:A+ 的配方 = 全链证书 + 只留 TLS1.2/1.3 + ECDHE 前向保密 + OCSP stapling + HSTS + 80 端口强跳。
以上就是Nginx配置HTTPS + HTTP/2的全过程及避坑指南的详细内容,更多关于Nginx配置HTTPS和HTTP/2实战的资料请关注脚本之家其它相关文章!
相关文章
Nginx服务器中HTTP 301跳转到带www的域名的方法
这篇文章主要介绍了Nginx服务器中HTTP 301跳转到带www的域名的方法,包括从HTTPS 301提示跳转等rewrite相关的方法,需要的朋友可以参考下2015-07-07


最新评论