极简工具箱

免费在线工具 · 本地计算 · 无需上传

Nginx 配 HTTPS:证书拼接、HTTP 跳转与 HTTP/2

证书配好了浏览器却提示「不受信任」,`curl` 也报错——多半是只下发了站点证书,中间证书没拼进去。

广告位(百度联盟)

一、完整配置示例

server {
    listen 80;
    server_name www.it586.cn it586.cn;
    return 301 https://www.it586.cn$request_uri;
}

server {
    listen 443 ssl;
    http2 on;
    server_name www.it586.cn;

    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers off;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    root /var/www/it586;
    index index.html;
    location / { try_files $uri $uri/ =404; }
}

旧版本 Nginx 用 listen 443 ssl http2;,1.25.1 之后改为 http2 on;,写错会报 unknown directive 或警告。

二、证书链必须拼接

cat www.it586.cn.crt intermediate.crt > fullchain.pem

顺序是站点证书在前、中间证书在后,根证书不需要。顺序反了或漏了中间证书,浏览器可能「自动补齐」看起来正常,但 curl、Java、部分移动端会报 unable to find valid certification path。

验证:

openssl s_client -connect www.it586.cn:443 -servername www.it586.cn -showcerts

输出里应该能看到至少两张证书。

三、80 跳 443 的正确写法

return 301 https://$host$request_uri;

要点:

注意:做这个跳转前先确认证书覆盖了裸域。如果证书只有 www.it586.cn,用户访问 https://it586.cn 会先看到证书错误,跳转都来不及发生。

四、TLS 版本与套件

五、HSTS 要谨慎

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

一旦下发,浏览器在 max-age 内强制用 HTTPS 访问,证书出问题时用户连「继续访问」都点不了。首次上线建议先用 max-age=300 试运行,确认证书续期正常后再加长。

六、续期之后

免费证书 90 天到期,自动续期后必须让 Nginx 重新加载:

certbot renew --quiet
nginx -s reload

只 renew 不 reload,Nginx 还在用内存里的旧证书,浏览器依旧报过期。建议在续期钩子里直接加 reload:

certbot renew --deploy-hook "nginx -s reload"

七、常见问题

现象原因
SSL_CTX_use_PrivateKey ... key values mismatch证书与私钥不配对
浏览器「不受信任」中间证书缺失或用了自签名
部分资源被拦截页面里还有 http:// 的图片/脚本(混合内容)
老客户端连不上只开了 TLS 1.3,或套件过严
证书过期但已续期没 reload

私钥文件权限建议 600,属主为 root,不要让 Nginx 以外的用户可读。

小结

fullchain.pem = 站点证书 + 中间证书,顺序不能反;80 端口用 301 带 $request_uri 跳转;只开 TLS 1.2/1.3;HSTS 先短后长;续期后必须 reload。

本文相关工具(本地计算,无需上传)

更多使用教程