Chapter 07

HTTPS 与 TLS

Nginx 是理想的 TLS 终止点。掌握证书配置、certbot 自动续期、强制跳转、HSTS 与协议优化,让你的站点又安全又快。

7.1 核心概念

TLS(Transport Layer Security)
为 HTTP 加密传输的协议(SSL 的继任者)。HTTPS = HTTP over TLS,保证数据加密、防篡改、验证服务器身份。
TLS 终止(TLS Termination)
在 Nginx 处解密 HTTPS,再以明文 HTTP 转发给内网后端。后端无需处理证书,集中管理更省心。
证书与私钥
fullchain.pem 是服务器证书+中间证书链,privkey.pem 是配对私钥。私钥绝不能泄露,权限设为 600。
Let's Encrypt / certbot
免费的自动化证书颁发机构,certbot 是其官方客户端,能自动签发和续期(证书有效期 90 天)。
HSTS(HTTP Strict Transport Security)
一个响应头,告诉浏览器"以后一律用 HTTPS 访问本站",防止降级攻击和首次跳转的中间人风险。
HTTP/2 与 HTTP/3
HTTP/2 多路复用一条连接、头部压缩;HTTP/3 基于 QUIC(UDP),避免队头阻塞、握手更快。二者都需在 TLS 上启用。

7.2 基础 HTTPS 配置

server {
    listen  443  ssl;
    listen  [::]:443  ssl;
    http2  on;                        # 1.25.1+ 用独立指令开启 HTTP/2
    server_name  example.com;

    ssl_certificate      /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/example.com/privkey.pem;

    root  /var/www/example;
    location / {
        try_files  $uri /index.html;
    }
}

7.3 用 certbot 自动签发

# 安装 certbot 及 Nginx 插件
$ sudo apt install certbot python3-certbot-nginx

# 自动签发并改写 Nginx 配置
$ sudo certbot --nginx -d example.com -d www.example.com

# 测试自动续期(证书 90 天,certbot 会装定时任务)
$ sudo certbot renew --dry-run
续期后要 reload Nginx

certbot 续期只是更新了证书文件,Nginx 还在用内存里的旧证书。certbot 的续期钩子通常会自动 reload,但自签或手动流程里别忘了 systemctl reload nginx,否则新证书不生效。

7.4 HTTP 强制跳转 HTTPS

# 80 端口只负责跳转到 443
server {
    listen  80;
    listen  [::]:80;
    server_name  example.com www.example.com;
    return  301  https://$host$request_uri;
}
用 return 301,别用 rewrite + if

网上很多老教程用 if ($scheme = http) { rewrite ... } 做跳转。更简洁高效的是单独一个 return 301 的 server 块。Nginx 社区名言 "if is evil"——在 location 里滥用 if 容易出诡异 bug,能用 return/try_files 就别用 if。

7.5 TLS 协议与套件优化

http {
    # 只留现代协议,禁用不安全的旧版本
    ssl_protocols  TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers  off;   # TLS1.3 下让客户端选更优
    ssl_ciphers  ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;

    # 会话复用,减少重复握手
    ssl_session_cache  shared:SSL:10m;
    ssl_session_timeout  1d;
    ssl_session_tickets  off;

    # OCSP Stapling:由服务器代查证书吊销状态,加速握手
    ssl_stapling  on;
    ssl_stapling_verify  on;
}

7.6 HSTS 与安全头

server {
    listen 443 ssl;
    # 告诉浏览器一年内强制 HTTPS,含子域
    add_header  Strict-Transport-Security  "max-age=31536000; includeSubDomains"  always;
    add_header  X-Content-Type-Options  "nosniff"  always;
    add_header  X-Frame-Options  "SAMEORIGIN"  always;
    add_header  Referrer-Policy  "strict-origin-when-cross-origin"  always;
}
HSTS 是不可逆承诺

一旦发了 HSTS 头,浏览器在 max-age 期内拒绝任何 HTTP 访问该域,包括你自己调试时。上线 includeSubDomainspreload 前务必确认所有子域都已支持 HTTPS,否则子域会集体无法访问,且无法快速回退。always 参数确保错误响应也带此头。

7.7 开启 HTTP/3(QUIC)

server {
    listen  443  ssl;
    listen  443  quic  reuseport;    # HTTP/3 走 UDP 443
    http2  on;
    http3  on;
    server_name  example.com;

    ssl_certificate      /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/example.com/privkey.pem;

    # 通告客户端本站支持 HTTP/3
    add_header  Alt-Svc  'h3=":443"; ma=86400';
}
HTTP/3 需要较新的 Nginx

HTTP/3 从 Nginx 1.25.0 起进入主线(需编译时带 QUIC 支持)。别忘了在防火墙/安全组放行 UDP 443——很多人只开了 TCP 443,结果 HTTP/3 静默失败、回退到 HTTP/2 还不自知。

7.8 小结与下一步