3. 搭建 HTTPS Web 服务器:Nginx 配置实战

好,我们进入第三章。前两章我们把证书签发了,也理解了握手原理。这一章很实在——把 Nginx 配起来,让 HTTPS 真正跑通。

我个人习惯,不管项目多急,都会先在本地搭一遍。你想想看,线上环境出问题排查成本太高了。本地搞通了,再推到生产,心里有底。

3.1 基础环境准备

假设你已经装好了 Nginx。没装的话,CentOS 用 yum install nginx,Ubuntu 用 apt install nginx。版本最好在 1.18 以上,老版本对 HTTP/2 和现代密码套件支持不太好。

检查一下当前版本:

nginx -v
# nginx version: nginx/1.24.0

嗯,这里要注意:确认编译参数里有没有 --with-http_ssl_module。没有的话,后面配 HTTPS 会报错。

nginx -V 2>&1 | grep ssl
# 输出里应该有 --with-http_ssl_module
踩坑提醒: 我曾经在生产服务器上遇到过,用 yum 安装的 Nginx 居然没带 SSL 模块。最后只能重新编译。所以,装完后第一件事就是检查这个。

3.2 配置 SSL 证书与 HTTPS 服务

把上一章签发的证书文件准备好。假设你的证书放在 /etc/nginx/ssl/ 目录下:

  • example.com.crt — 服务器证书
  • example.com.key — 私钥文件
  • ca.crt — 中间证书链(如果有的话)

我建议把证书链合并成一个文件,Nginx 处理起来更干净:

cat example.com.crt ca.crt > fullchain.crt

然后编辑 Nginx 配置文件。我个人习惯把 HTTPS 配置单独放在 /etc/nginx/conf.d/ssl.conf,方便管理。

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate     /etc/nginx/ssl/fullchain.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers on;

    location / {
        root   /var/www/html;
        index  index.html;
    }
}

这里有几个关键点:

  • listen 443 ssl http2 — 同时启用 SSL 和 HTTP/2。HTTP/2 能显著提升并发性能,我实测过,页面加载能快 30% 以上。
  • ssl_protocols — 只允许 TLSv1.2 和 TLSv1.3。SSLv3 和 TLSv1.0/1.1 都太老了,有已知漏洞。
  • ssl_ciphers — 只选强加密套件。ECDHE 提供前向安全性,AES-GCM 是硬件加速的。
小技巧: 配置完后,用 nginx -t 测试语法。我每次改完配置都会跑一遍,避免手误导致服务重启失败。

3.3 强制 HTTPS 重定向

光配好 443 端口还不够。用户可能直接输入 http://example.com,这时候需要把 HTTP 请求重定向到 HTTPS。

配置很简单,加一个监听 80 端口的 server 块:

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

301 是永久重定向。浏览器收到后会记住这个跳转,下次直接访问 HTTPS。不过,我建议第一次部署时先用 302 临时重定向,等确认 HTTPS 完全正常了再改成 301。

为什么会这样?因为 301 会被浏览器缓存,万一你配错了,用户得清缓存才能恢复。我吃过这个亏,线上配完发现证书有问题,结果用户死活访问不了,排查了半天才发现是浏览器缓存了 301。

3.4 安全加固与性能优化

基础配置跑通了,我们再加几层防护。这些是我在项目中总结出来的「必选项」:

配置项 推荐值 说明
ssl_session_cache shared:SSL:10m 缓存 SSL 会话,减少握手开销。10m 大约能存 40000 个会话
ssl_session_timeout 10m 会话超时时间,太短会增加握手次数,太长有安全风险
ssl_stapling on OCSP Stapling,让 Nginx 代浏览器查询证书吊销状态,提升访问速度
ssl_stapling_verify on 验证 OCSP 响应签名,防止伪造
add_header Strict-Transport-Security max-age=31536000; includeSubDomains HSTS 头,告诉浏览器强制使用 HTTPS,连第一次 HTTP 请求都省了

把这些加到你的 HTTPS 配置里:

server {
    listen 443 ssl http2;
    server_name example.com;

    # 证书配置
    ssl_certificate     /etc/nginx/ssl/fullchain.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;

    # 协议与加密套件
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers on;

    # 会话缓存
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location / {
        root   /var/www/html;
        index  index.html;
    }
}
核心要点: HSTS 头一旦设置,浏览器会在指定时间内强制 HTTPS。如果你还没完全迁移好,先别加 includeSubDomains,否则子域名 HTTP 服务会全部失效。

3.5 验证配置

配置写完了,重启 Nginx:

nginx -t          # 测试语法
systemctl reload nginx   # 重新加载配置

然后用浏览器访问 https://example.com,地址栏应该出现小锁图标。点开证书信息,确认签发机构、有效期都正确。

我习惯再用命令行验证一遍:

curl -I https://example.com
# 返回头里应该有 HTTP/2 200 和 strict-transport-security

检查重定向是否生效:

curl -I http://example.com
# 应该返回 301 Moved Permanently,Location 指向 HTTPS 地址

最后,用在线工具(比如 SSL Labs)扫一遍,看看评级。A 级是及格线,A+ 才放心。我一般会盯着这几个指标:

  • 证书链是否完整
  • 是否支持前向安全性
  • 是否启用 HSTS
  • 是否禁用不安全的协议

3.6 核心流程回顾

这一章的内容,说白了就是三步:配证书、开 HTTPS、强制定向。但每一步都有细节,漏一个就可能出问题。

下面这张图总结了整个配置流程,你可以对照着检查自己的配置:

HTTPS 配置核心流程 准备证书与私钥 配置 443 端口 设置安全参数 配置 HTTP→HTTPS 重定向 验证与测试 证书链要完整 私钥权限设为 600 启用 HTTP/2 监听 443 ssl TLSv1.2 + TLSv1.3 开启 OCSP Stapling 301 永久重定向 添加 HSTS 头 nginx -t 测试语法 SSL Labs 评级 A+ 避坑清单 • 证书路径不要写错 • 私钥权限必须 600 • 不要用 SSLv3/TLSv1.0 • 301 重定向慎用 • HSTS 先不加 includeSubDomains • 防火墙放行 443 端口 • SELinux 可能拦截 • 证书到期前 30 天提醒 • 不要用自签名证书上生产 • 测试环境用 302 临时重定向 • 定期检查 OCSP 响应 • 日志里监控 4xx/5xx 错误

嗯,这一章就到这里。配置 HTTPS 其实不复杂,但每一步都关系到安全性和可用性。你按这个流程走一遍,应该能跑通。如果遇到问题,先检查证书路径和端口监听,这两个地方最容易出错。