Nginx HTTPS 与证书配置方案(certbot/自签名)
为 Nginx 配置 HTTPS,包括使用 Certbot 申请/续期 Let's Encrypt 免费证书、生成自签名证书、以及在 server 块启用 SSL。适用于 Ubuntu 22.04
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_cache | off/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
参考链接
- Nginx SSL 模块:https://nginx.org/en/docs/http/ngx_http_ssl_module.html
- Certbot:https://certbot.eff.org
- Let's Encrypt 文档:https://letsencrypt.org/docs/