Certbot 证书自动化教程 / 第 6 章:Nginx 集成
第 6 章:Nginx 集成
6.1 Nginx 插件概述
Certbot 的 Nginx 插件是功能最强大的集成方式之一。它不仅能自动完成域名验证,还能自动修改 Nginx 配置文件,实现 SSL/TLS 的一键部署。
插件能力
| 功能 | 说明 |
|---|---|
| 自动验证 | 通过 Nginx 响应 ACME 验证请求 |
| 自动配置 SSL | 修改 Nginx 配置,添加 SSL 证书路径 |
| HTTPS 重定向 | 自动添加 HTTP → HTTPS 重定向规则 |
| SSL 参数优化 | 自动添加推荐的 SSL 安全参数 |
| 多域名支持 | 在一个证书中包含多个域名 |
与 Webroot 模式对比
| 特性 | Nginx 插件 | Webroot 模式 |
|---|---|---|
| 自动修改 Nginx 配置 | ✅ 是 | ❌ 否 |
| 需要手动配置 Nginx | ❌ 否 | ✅ 是 |
| 配置可控性 | 中(自动配置) | 高(手动配置) |
| 适合新手 | ✅ 非常适合 | 需要 Nginx 经验 |
| 适合复杂场景 | 有限 | ✅ 灵活 |
6.2 安装与基本使用
安装 Nginx 插件
# Snap 安装(已内置 Nginx 插件)
sudo snap install --classic certbot
# apt 安装
sudo apt install -y certbot python3-certbot-nginx
# dnf 安装
sudo dnf install -y python3-certbot-nginx
确认 Nginx 已运行
# 检查 Nginx 状态
sudo systemctl status nginx
# 确认 Nginx 配置文件存在
ls /etc/nginx/sites-enabled/
# 或
ls /etc/nginx/conf.d/
基本命令
# 为单个域名申请证书并自动配置 Nginx
sudo certbot --nginx -d example.com
# 为多个域名申请证书
sudo certbot --nginx -d example.com -d www.example.com
# 交互式选择域名
sudo certbot --nginx
# 仅获取证书,不修改 Nginx 配置
sudo certbot certonly --nginx -d example.com
执行过程
运行 certbot --nginx 后,Certbot 会:
- 读取 Nginx 配置文件,识别匹配的 server 块
- 通过 Nginx 响应 ACME HTTP-01 验证
- 申请证书
- 修改 Nginx 配置,添加 SSL 相关指令
- 可选:添加 HTTP → HTTPS 重定向
- 测试 Nginx 配置语法
- 重新加载 Nginx
6.3 Nginx 配置自动修改
修改前的配置
# /etc/nginx/sites-available/example.com
server {
listen 80;
server_name example.com www.example.com;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
修改后的配置
# /etc/nginx/sites-available/example.com
server {
listen 80;
server_name example.com www.example.com;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
选择是否添加 HTTPS 重定向
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
选择 2 后的配置:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri; # managed by Certbot
}
server {
listen 443 ssl;
server_name example.com www.example.com;
root /var/www/html;
index index.html;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
6.4 反向代理 HTTPS 配置
典型场景:Nginx 反向代理后端应用
# HTTP 重定向
server {
listen 80;
server_name app.example.com;
return 301 https://$host$request_uri;
}
# HTTPS 反向代理
server {
listen 443 ssl;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# 反向代理配置
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
申请证书后配置反向代理
# 1. 先用 Certbot Nginx 插件申请证书
sudo certbot --nginx -d app.example.com
# 2. 修改 Nginx 配置,添加反向代理
sudo vim /etc/nginx/sites-available/app.example.com
WebSocket 反向代理配置
server {
listen 443 ssl;
server_name ws.example.com;
ssl_certificate /etc/letsencrypt/live/ws.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ws.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
location /ws {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
6.5 SSL 安全加固
Certbot 生成的 SSL 配置
Certbot 创建的 /etc/letsencrypt/options-ssl-nginx.conf 内容:
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
增强 SSL 配置
在 Certbot 生成的配置基础上,可以进一步加固:
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;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# 安全响应头
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
}
OCSP Stapling 说明
| 参数 | 说明 |
|---|---|
ssl_stapling on | 启用 OCSP Stapling |
ssl_stapling_verify on | 验证 OCSP 响应 |
ssl_trusted_certificate | OCSP 验证的证书链 |
resolver | DNS 解析器(用于 OCSP 查询) |
resolver_timeout | DNS 查询超时时间 |
提示: OCSP Stapling 可以加速 TLS 握手,减少客户端向 CA 查询证书吊销状态的延迟。
6.6 HTTP/2 与 HTTP/3
HTTP/2 配置
# HTTP/2 已包含在 Certbot 的配置中
server {
listen 443 ssl http2;
# ... SSL 配置
}
HTTP/3 (QUIC) 配置
# Nginx 1.25.0+ 支持 HTTP/3
server {
listen 443 ssl;
listen 443 quic reuseport; # HTTP/3
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 告知客户端支持 HTTP/3
add_header Alt-Svc 'h3=":443"; ma=86400';
# ... 其他配置
}
注意: HTTP/3 使用 UDP 协议,需要在防火墙上开放 443/UDP。
6.7 多站点配置
场景:一台 Nginx 托管多个 HTTPS 站点
# 申请多个证书
sudo certbot --nginx \
-d site1.com -d www.site1.com \
-d site2.com -d www.site2.com \
-d api.site3.com
# 或分别为每个站点申请
sudo certbot --nginx -d site1.com -d www.site1.com
sudo certbot --nginx -d site2.com -d www.site2.com
sudo certbot --nginx -d api.site3.com
使用通配符证书
# 使用 DNS 验证申请通配符证书
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
-d example.com \
-d "*.example.com"
# 手动配置 Nginx 使用通配符证书
sudo vim /etc/nginx/sites-available/app.example.com
server {
listen 443 ssl;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root /var/www/app;
}
6.8 Nginx 配置模板
标准 HTTPS 站点模板
# /etc/nginx/snippets/ssl-params.conf
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 off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
# /etc/nginx/snippets/ssl-example.com.conf
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# /etc/nginx/sites-available/example.com.conf
# HTTP 重定向
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS 站点
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
include /etc/nginx/snippets/ssl-example.com.conf;
include /etc/nginx/snippets/ssl-params.conf;
root /var/www/example.com;
index index.html;
# 日志
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
location / {
try_files $uri $uri/ =404;
}
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
6.9 Nginx 插件排错
常见错误
错误 1:无法找到 Nginx 配置
Certbot could not find a matching server block
解决方案:
# 确认 sites-enabled 中有对应的软链接
ls -la /etc/nginx/sites-enabled/
# 创建软链接
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
# 重载 Nginx
sudo nginx -t && sudo systemctl reload nginx
错误 2:server_name 不匹配
No matching server block found
解决方案:
# 确认 server_name 包含了要申请证书的域名
grep "server_name" /etc/nginx/sites-enabled/*
# 确保 -d 参数的域名与 server_name 一致
错误 3:Nginx 配置测试失败
nginx: [emerg] unexpected "}" in /etc/nginx/...
解决方案:
# 检查 Nginx 配置
sudo nginx -t
# 修复配置错误后重试
sudo certbot --nginx -d example.com
6.10 最佳实践
- 使用
--nginx一键部署: 对于简单的场景,让 Certbot 自动配置 - 生产环境手动微调: 申请证书后,手动优化 SSL 配置和安全响应头
- 使用 snippet 复用配置: 将 SSL 参数放在 snippet 中,多个站点共享
- 开启 OCSP Stapling: 加速 TLS 握手,改善用户体验
- 配置 HSTS: 告知浏览器始终使用 HTTPS 访问
- 定期检查 SSL 配置: 使用 SSL Labs 测试