服务器 > 网络 > https

Nginx配置HTTPS + HTTP/2的全过程及避坑指南

5人参与 2026-09-18 https

给站点配好 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+。

小结

以上就是nginx配置https + http/2的全过程及避坑指南的详细内容,更多关于nginx配置https和http/2实战的资料请关注代码网其它相关文章!

(0)

您想发表意见!!点此发布评论

推荐阅读

Nginx反向代理配置的完整指南

09-18

Nginx 日志自动轮转(logrotate)

08-29

Nginx防御HTTP Host头攻击实战

08-29

Nginx HTTPS配置的实现指南

08-04

Nginx fair模块安装的实现

07-30

Nginx中host变量:$http_host、$host与$proxy_host的区别小结

07-30

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论