广告位 · 页头(后台-模块管理-新建模块后替换此区域)

如何在Nginx中开启HTTPS并正确配置SSL证书?

Nginx 开启 HTTPS 并不复杂,核心是在虚拟主机配置中监听 443 端口、指定 SSL 证书与私钥文件,并把原来 80 端口的访问平滑迁移或跳转到加密通道。做完这些后,流量在客户端与服务器之间会通过 TLS 握手建立加密连接,防止内容被窃听或篡改。对于已经运行 HTTP 站点的场景,只需要在现有配置基础上增加 SSL 相关指令即可,不必重构整个站点结构。

如何在Nginx中开启HTTPS并正确配置SSL证书?

一、准备SSL证书与私钥文件

启用 HTTPS 前必须先准备好证书文件和对应的私钥。证书可以来自 Let's Encrypt 这类免费 CA,也可以购买商业证书,还可以在测试环境使用 OpenSSL 生成自签名证书。无论哪种方式,最终都需要向 Nginx 提供两个核心文件:一个是包含站点公钥信息的证书文件,另一个是只有服务器自己持有的私钥文件。

以 Let's Encrypt 为例,使用 certbot 申请证书后,通常会得到 fullchain.pem 和 privkey.pem 两个文件。其中 fullchain.pem 包含站点证书和中间证书,能够组成完整证书链,适合直接交给 Nginx;privkey.pem 是对应的私钥。商业证书通常也会提供类似的文件,有时需要把站点证书和中间 CA 证书合并成一个文件。自签名证书则可以用一条 OpenSSL 命令快速生成,适合本地调试。

mkdir -p /etc/nginx/ssl
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/ipipp.com.key \
  -out /etc/nginx/ssl/ipipp.com.crt \
  -subj '/CN=ipipp.com'

证书文件通常可以设置为 644 权限,但私钥文件必须严格限制为 600,避免其他系统用户读取。可以使用 chmod 600 /etc/nginx/ssl/ipipp.com.key 命令收紧权限。正式环境中不要使用自签名证书,因为浏览器会直接提示不受信任,普通用户无法正常访问。

二、配置Nginx的HTTPS server块

准备好证书后,就可以在 Nginx 配置中增加一个监听 443 端口的 server 块。下面是一份基础配置,站点根目录仍指向原来的 Web 目录,但所有请求都会经过 TLS 加密。

server {
    listen 443 ssl;
    server_name ipipp.com;
    ssl_certificate     /etc/nginx/ssl/ipipp.com.crt;
    ssl_certificate_key /etc/nginx/ssl/ipipp.com.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
    ssl_prefer_server_ciphers on;
    location / {
        root /var/www/html;
        index index.html;
    }
}

这里 listen 443 ssl 表示同时监听 443 端口并启用 SSL 模块。ssl_certificate 指向证书文件,ssl_certificate_key 指向私钥文件。ssl_protocols 只保留 TLSv1.2 和 TLSv1.3,能够避免旧版本 TLS 带来的安全问题。ssl_ciphers 配置了当前较为主流的加密套件,优先使用 ECDHE 前向保密算法。开启 ssl_prefer_server_ciphers 后,服务器会优先选择自己定义的加密套件顺序,减少客户端选择弱算法的可能。

如果站点需要支持 HTTP/2,可以在 listen 指令后追加 http2,例如 listen 443 ssl http2;。不同 Nginx 版本对 http2 的写法略有差异,建议以当前安装版本的官方文档为准。配置完成后先执行 nginx -t 测试语法,再通过 systemctl reload nginx 让配置生效。

三、把HTTP请求强制跳转到HTTPS

仅仅配置 443 端口还不够,如果用户直接访问 http://ipipp.com,Nginx 仍然会以明文方式响应。为了让所有访问都走加密通道,需要为 80 端口配置一个跳转 server 块。比较推荐的做法是返回 301 永久重定向。

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

这里 $host 会保留用户访问时使用的域名,$request_uri 会保留原始路径和查询参数,这样跳转后不会丢失用户想访问的具体页面。使用 301 而不是 302 的原因是 301 表示永久移动,搜索引擎会逐渐把权重转移到 HTTPS 版本,对 SEO 更友好。302 则属于临时跳转,通常只在维护或调试时使用。

完成跳转后,如果希望进一步强化安全,可以增加 HSTS 响应头。它的作用是告诉浏览器以后只能通过 HTTPS 访问该域名,即使用户手动输入 http:// 也会被浏览器自动改写为 https://。配置方式如下:

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

HSTS 的 max-age 单位为秒,上面的配置表示一年内都强制使用 HTTPS。includeSubDomains 表示对子域名同样生效。建议在确认 HTTPS 稳定运行后再添加 HSTS,否则一旦证书配置出错,用户在有效期内将无法通过 HTTP 访问站点。

四、优化TLS性能与稳定性

HTTPS 会增加一次 TLS 握手过程,如果每次请求都重新协商,会带来一定延迟。Nginx 可以通过会话缓存和 OCSP Stapling 等机制降低握手开销,提升用户访问速度。

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

ssl_session_cache 会分配一块共享内存用于保存 TLS 会话参数,客户端在一定时间内重连时可以复用会话,省去完整的非对称加密计算。shared:SSL:10m 表示分配 10MB 内存,大约可以存储几万个会话。ssl_session_timeout 控制会话的有效时间,10 分钟在安全和性能之间比较平衡。

OCSP Stapling 的作用是由服务器代替客户端向 CA 查询证书吊销状态,并把结果附加在 TLS 握手中返回给客户端。这样浏览器就不必自己发起 OCSP 查询,既能加快握手速度,也能减少对 CA 服务器的请求压力。开启 ssl_stapling_verify 后需要配置 resolver 指向可用的 DNS 服务器,否则验证过程可能超时。

五、验证配置与常见问题排查

修改完配置后,不要直接重启 Nginx,而应该先执行 nginx -t 检查配置文件语法。如果输出 syntax is ok 和 test is successful,再执行 systemctl reload nginx 平滑加载配置。加载成功后,可以用 curl 命令快速验证 HTTPS 是否正常响应。

nginx -t
systemctl reload nginx
curl -I https://ipipp.com

如果 curl 返回正常的 HTTP/1.1 200 OK 或 301 状态码,说明 HTTPS 服务已经可以被访问。还可以使用 openssl s_client 查看证书链和协议版本,命令如下:

openssl s_client -connect ipipp.com:443 -servername ipipp.com

这条命令会打印出证书信息、协议版本、加密套件等内容。如果出现 unable to verify the first certificate,通常是因为证书链不完整,需要检查 ssl_certificate 是否指向了包含中间证书的 fullchain 文件。如果提示私钥不匹配,可以用下面的命令比对证书和私钥的 modulus 值是否一致。

openssl x509 -noout -modulus -in /etc/nginx/ssl/ipipp.com.crt | openssl md5
openssl rsa -noout -modulus -in /etc/nginx/ssl/ipipp.com.key | openssl md5

两行命令输出的 MD5 值应当完全相同。如果不同,说明证书和私钥不是一对,需要重新生成或重新下载匹配文件。另一个常见问题是 443 端口被防火墙或云安全组拦截,导致外部无法访问,但本机 curl 正常。这种情况需要检查 iptables、firewalld 以及云控制台的安全组规则。私钥文件权限过宽也可能导致 Nginx 启动失败或警告,务必使用 chmod 600 限制私钥权限。

广告位 · 文章底部(后台-模块管理替换此区域)