Nginx HTTPS 与证书配置方案(certbot/自签名)

为 Nginx 配置 HTTPS,包括使用 Certbot 申请/续期 Let's Encrypt 免费证书、生成自签名证书、以及在 server 块启用 SSL。适用于 Ubuntu 22.04

NginxnginxhttpscertbotWeb 服务器与反向代理Web 服务器反向代理2026/09/27

Nginx HTTPS 与证书配置方案(certbot/自签名)

目标:为 Nginx 配置 HTTPS,包括使用 Certbot 申请/续期 Let's Encrypt 免费证书、生成自签名证书、以及在 server 块启用 SSL。适用于 Ubuntu 22.04。

环境信息

  • 操作系统:Ubuntu 22.04.5 LTS
  • Nginx:1.18.0(Ubuntu,默认已编译 --with-http_ssl_module)
  • 工具:certbot、openssl
  • 证书目录:/etc/letsencrypt(Certbot)、自定义路径(自签名)

前置条件

apt-get update
apt-get install -y nginx openssl
# 编译安装的 nginx 需确认含 ssl 模块
nginx -V | grep -o with-http_ssl_module

HTTPS 原理简述

HTTPS = HTTP + SSL/TLS。流程:客户端发起请求 → 服务端返回证书(公钥+元信息)→ 客户端校验颁发机构/有效期并生成随机值加密后发给服务端 → 服务端用私钥解密得到会话密钥 → 后续用该对称密钥加密通信。证书即"公钥+私钥"对,公钥公开、私钥仅服务端持有。

⚠️ 说明:nginx 的 ssl 功能基于 ngx_http_ssl_module。apt 安装默认已启用;源码编译安装需在 configure 时加 --with-http_ssl_module。

方案一:Certbot 申请 Let's Encrypt 证书(推荐,自动续期)

1. 安装 certbot 及 Nginx 插件

apt-get install -y certbot python3-certbot-nginx

2. 自动获取并配置证书

确保域名已解析到本服务器,Nginx 对应站点已存在且 80 端口可被 ACME 校验访问:

certbot --nginx -d example.com -d www.example.com
  • 会自动完成证书申请并把 server 块切换为 443 SSL;
  • 若只想获取证书手动配置:certbot certonly --nginx -d example.com。

💡 说明:申请时要求 .well-known/acme-challenge/ 能被 Web 服务访问;域名必须已别解析到服务器。

3. 测试 SSL

curl -sI https://example.com | head -3
# 或浏览器访问,地址栏有锁标识;可再用 https://www.ssllabs.com/ssltest 深度扫描

4. 自动续期(Let's Encrypt 证书效期 90 天)

# 试运行(不会真正续期,验证能否续到)
certbot renew --dry-run
# 真正的续期命令(一般由 timer 定期执行)
certbot renew
# 续期后让 nginx 生效
nginx -s reload

将自动续期加入系统计划任务:

crontab -e
# 每月 1、15 日凌晨 3 点续期并在成功后 reload nginx
0 3 */15 * * certbot renew --quiet && nginx -s reload

⚠️ 说明:Let's Encrypt 证书跨域(通配符)需要 DNS 校验,命令如 certbot certonly --manual -d "*.example.com",需按提示在 DNS 添加 TXT 记录(_acme-challenge)后再回车确认。

方案二:自签名证书(内网/测试用)

# 1. 生成私钥并生成 CSR(CN 填服务器 IP 或域名)
openssl req -new -newkey rsa:2048 -nodes \
  -keyout /etc/ssl/private/example.key \
  -subj "/CN=example.com" -out /tmp/example.csr

# 2. 自签名签发证书(有效 365 天)
openssl x509 -req -days 365 \
  -in /tmp/example.csr \
  -signkey /etc/ssl/private/example.key \
  -out /etc/ssl/certs/example.crt

💡 说明:自签名证书不受浏览器信任,浏览器会告警,仅限内网/联调。

针对 IP 的自签名证书(内网测试常用)

自签名证书的 CN 可填 IP 而非域名(许多浏览器对纯 IP 的 HTTPS 证书显示"不安全"属正常,内网/联调可用):

# 1. 生成私钥 + 自签名证书(CN 填服务器 IP)
openssl req -x509 -newkey rsa:2048 -nodes -days 365 \
  -keyout /etc/ssl/private/server.key \
  -subj "/CN=192.168.1.100" \
  -out /etc/ssl/certs/server.crt
chmod 600 /etc/ssl/private/server.key
# 查看证书信息
openssl x509 -in /etc/ssl/certs/server.crt -noout -subject -dates

💡 说明:-x509 一步生成自签名证书,省去 CSR 中间步骤;-days 365 为有效期。若已有 CSR 想签发,可用 openssl x509 -req -in csr.csr -signkey key.pem -out cert.crt。

Nginx server 块启用 HTTPS

简化配置(最小可用)

server {
    listen 443 ssl;                 # 注意:用 listen ssl 而非 ssl on
    server_name example.com;
    ssl_certificate     /etc/ssl/certs/example.crt;
    ssl_certificate_key /etc/ssl/private/example.key;
    root /var/www/html;
    index index.html;
}

服务器内实测结果(openssl 自签名 + nginx)

在 Ubuntu 22.04 服务器上生成自签名证书、配置 listen 443 ssl 后实测:

  • curl -sk https://localhost/(-k 忽略自签名告警)→ 200 且 via HTTPS;
  • 80 端口配置 return 301 https://$host$request_uri; 后,curl -I http://localhost/ → 301 且 Location: https://…;
  • 配置 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; 后,响应头可见 Strict-Transport-Security: max-age=31536000; includeSubDomains。

⚠️ 说明:自签名证书浏览器会拦截,测试用 curl -k;生产请用 Certbot/权威 CA。Nginx 1.18(OpenSSL 3.0)默认支持 TLSv1.3。

配置样例(/etc/nginx/sites-available/example.com):

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com;

    # 证书与私钥
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # 协议与缓存(生产建议)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_cache shared:SSL:10m;      # 各 worker 共享缓存,1M≈4000 会话
    ssl_session_timeout 10m;
    ssl_prefer_server_ciphers on;
    ssl_ciphers HIGH:!aNULL:!MD5;

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

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

💡 说明:

  • ssl on 指令已被 listen 443 ssl 取代,勿再写旧写法;
  • 自签名证书路径替换为自签名生成的 .crt/.key;
  • fullchain.pem = 站点证书 + 中间证书链,Certbot 会生成。

常用 SSL 参数速查

参数说明
ssl_certificate证书链文件(crt/fullchain.pem)
ssl_certificate_key私钥文件(key/privkey.pem)
ssl_protocols允许的 TLS 版本,禁 SSLv2/SSLv3
ssl_session_cacheoff/none/builtin/shared:name:size
ssl_session_timeout会话缓存有效期,默认 5m
ssl_prefer_server_ciphers服务端优先选择加密套件

官方性能建议

worker_processes auto;
http {
    server {
        listen 443 ssl;
        keepalive_timeout 70;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_certificate     /path/cert.pem;
        ssl_certificate_key /path/cert.key;
        ssl_session_cache  shared:SSL:10m;
        ssl_session_timeout 10m;
    }
}

要点:worker 数=CPU 数、开 keep-alive、共享会话缓存、禁内置缓存、延长会话有效期以降 CPU 开销。

生产 HTTPS 加固:安全响应头 / HSTS / OCSP

目标:在已能跑通 HTTPS 的基础上,补充安全性。以下内容可在服务器上用自签名证书实测响应头,生产用权威证书同理。

server {
    listen 443 ssl http2;
    server_name example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # HSTS:强制浏览器今后只用 HTTPS 访问本域(seconds;includeSubDomains 覆盖子域)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    # 防点击劫持
    add_header X-Frame-Options "SAMEORIGIN" always;
    # MIME 嗅探防护
    add_header X-Content-Type-Options "nosniff" always;
    # 防 CRLF 注入/缓存混淆
    add_header X-XSS-Protection "1; mode=block" always;

    # OCSP Stapling:由 nginx 定期拉取吊销状态并随握手返回,省去客户端二次请求,降低首连时延
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 1.1.1.1 valid=300s;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

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

关键点实测说明:

  • add_header ... always 会覆盖同级别下可能冲突的 header,多个 add_header 需分别写完整;
  • 上面的安全头在服务器上通过 curl -sk https://host/ -I 均可逐个看到;
  • ocsp/stapling 在离线/无外网环境无法实测(需访问 CA 的 OCSP 服务器),生产在线环境才生效。

一键验证证书与站点

# 校验本地证书
openssl x509 -in /etc/ssl/certs/test.crt -noout -text
# 通过域名检查证书链(本机对外)
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -dates

常见问题

  • [emerg] cannot load certificate key:私钥与证书不匹配或路径错误/权限不足,校验 nginx -t;私钥建议 600 权限。
  • 浏览器报证书不可信:用的是自签名或被吊销证书;生产请用 Let's Encrypt/权威 CA。
  • certbot 无法校验域名:确认域名已解析到本机、80/443 端口放行、无 CDN 缓存 ACME 路径。
  • 升级新版 nginx 后 ssl on 警告:改为 listen 443 ssl;。

卸载方式

# 删除 Certbot 证书
certbot delete --cert-name example.com
# 卸载 certbot
apt-get remove -y certbot python3-certbot-nginx

参考链接