强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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 会:

  1. 读取 Nginx 配置文件,识别匹配的 server 块
  2. 通过 Nginx 响应 ACME HTTP-01 验证
  3. 申请证书
  4. 修改 Nginx 配置,添加 SSL 相关指令
  5. 可选:添加 HTTP → HTTPS 重定向
  6. 测试 Nginx 配置语法
  7. 重新加载 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_certificateOCSP 验证的证书链
resolverDNS 解析器(用于 OCSP 查询)
resolver_timeoutDNS 查询超时时间

提示: 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 最佳实践

  1. 使用 --nginx 一键部署: 对于简单的场景,让 Certbot 自动配置
  2. 生产环境手动微调: 申请证书后,手动优化 SSL 配置和安全响应头
  3. 使用 snippet 复用配置: 将 SSL 参数放在 snippet 中,多个站点共享
  4. 开启 OCSP Stapling: 加速 TLS 握手,改善用户体验
  5. 配置 HSTS: 告知浏览器始终使用 HTTPS 访问
  6. 定期检查 SSL 配置: 使用 SSL Labs 测试

扩展阅读