广告位联系
返回顶部
分享到

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

nginx 来源:互联网 作者:佚名 发布时间:2026-09-18 22:41:23 人浏览
摘要

给站点配好 HTTPS,浏览器地址栏出现小锁头,很多人就以为搞定了。但拿去 SSL Labs(ssllabs.com/ssltest)一测,评分可能只有 B证书链不全导致部分客户端报错、支持了早已被攻破的 TLS 1.0、握手慢得肉眼

给站点配好 HTTPS,浏览器地址栏出现小锁头,很多人就以为搞定了。但拿去 SSL Labs(ssllabs.com/ssltest)一测,评分可能只有 B——证书链不全导致部分客户端报错、支持了早已被攻破的 TLS 1.0、握手慢得肉眼可见。这篇按「先能用、再安全、后提速」的顺序,把一份 Nginx HTTPS 配置从「有锁头」调到 SSL Labs A+,每一项都讲清楚为什么。

最小可用版:先让 HTTPS 跑起来

假设证书已经签好(Let’s Encrypt 或商业 CA),最小配置长这样:

1

2

3

4

5

6

7

8

9

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 指向的文件必须是「站点证书 + 中间证书」拼在一起的全链文件(顺序是站点证书在前、中间证书在后),不是只有站点证书那一张。

1

2

3

# Let's Encrypt 的 fullchain.pem 已经是全链,直接用它

# 商业 CA 通常给你 your_domain.crt 和 intermediate.crt 两个文件,需手动拼:

cat your_domain.crt intermediate.crt > /etc/nginx/ssl/example.com.crt

1

2

3

# 指向全链文件,不是单张站点证书

ssl_certificate     /etc/nginx/ssl/example.com.crt;   # fullchain

ssl_certificate_key /etc/nginx/ssl/example.com.key;

验证链是否完整,用 openssl 连一下看 Verify return code:

1

2

3

4

# 加 -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 后面那种在新版会告警):

1

2

3

4

5

6

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 淘汰)或弱加密套件。安全基线配置:

1

2

3

4

5

6

7

8

9

10

# 只留 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 代替浏览器提前查好,握手时直接把「证书有效」的凭证一起发下去,省掉浏览器那次外网请求:

1

2

3

4

5

6

7

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 是否生效:

1

2

3

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」,连第一跳都省了:

1

2

# 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,别让用户有机会走明文:

1

2

3

4

5

6

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 端口强跳。

版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计