Web 服务器

Nginx 用 Certbot 配置 Let's Encrypt 免费 HTTPS 证书

作者: · 最后核实

用 snap 安装 Certbot 后运行 certbot --nginx,就能为 Nginx 上的 example.com 和 www.example.com 申请 Let's Encrypt 免费证书。Certbot 会改好 HTTPS 配置和 HTTP 跳转,并在到期前自动续期。适用于 Ubuntu 22.04/24.04、Debian 12/13,Nginx 任意在维护的版本,Certbot 4.1 及以上(截至 2026 年 11 月最新是 5.x)。

前提条件

Let's Encrypt 需要能从公网通过 80 端口访问到你的服务器。

  • 一台带 systemd 的 Linux 服务器,有 sudo 权限。Ubuntu 自带 snap;Debian 先运行 sudo apt install snapd。
  • 已安装并运行 Nginx,域名有对应的 server 配置。
  • 域名 example.com、www.example.com 的 A 记录(用 IPv6 的话还有 AAAA 记录)指向服务器,例如 203.0.113.10。
  • 服务器在中国大陆的,域名必须已完成 ICP 备案,否则云厂商会拦截 80/443 端口的网站访问,HTTP 验证会失败。
  • 防火墙和云服务器安全组都放行 TCP 80 和 443。Let's Encrypt 会从多个地点同时验证,不要只对某几个 IP 开放 80 端口。

开始前先检查解析和防火墙:

dig +short example.com A
dig +short www.example.com A
sudo ufw allow 'Nginx Full'   # 用 ufw 时才需要

用宝塔面板管理网站的,直接看 宝塔面板配置 SSL 证书,不要再手动改宝塔生成的 Nginx 配置。

第一步:确认 Nginx 有这个域名的 server 配置

Certbot 的 Nginx 插件按 server_name 查找配置,名字必须和要申请的域名一致。只有 HTTP 的最小配置如下:

# /etc/nginx/sites-available/example.com
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/example.com;
    index index.html;
}

启用并检查配置:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

CentOS、Rocky 等系统没有 sites-enabled 目录,把配置放到 /etc/nginx/conf.d/example.com.conf 即可。

第二步:用 snap 安装 Certbot

snap 是 Certbot 官方推荐的安装方式,自带 Nginx 插件和续期定时器。先卸载系统源里的旧版 certbot,避免两个版本冲突:

sudo apt-get remove certbot          # 提示未安装可以忽略
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
certbot --version

不能用 snap 时,官方也提供 pip + 虚拟环境的安装方式(官方称“尽力支持”):

sudo apt update
sudo apt install python3 python3-dev python3-venv libaugeas-dev gcc
sudo python3 -m venv /opt/certbot/
sudo /opt/certbot/bin/pip install --upgrade pip
sudo /opt/certbot/bin/pip install certbot certbot-nginx
sudo ln -s /opt/certbot/bin/certbot /usr/local/bin/certbot

国内服务器 pip 下载慢,可以在 pip install 后面加 -i https://pypi.tuna.tsinghua.edu.cn/simple 使用国内镜像。

第三步:申请证书并自动配置 Nginx

一条命令完成 HTTP-01 验证、签发证书、往 server 配置里加 HTTPS 设置并重载 Nginx:

sudo certbot --nginx -d example.com -d www.example.com

过程中需要同意 Let's Encrypt 用户协议,邮箱可以不填:Let's Encrypt 从 2025 年 6 月 4 日起已不再发送到期提醒邮件。在脚本里运行时用非交互模式:

sudo certbot --nginx --non-interactive --agree-tos \
  -d example.com -d www.example.com

想自己改 Nginx 配置的,用 sudo certbot certonly --nginx -d example.com -d www.example.com 只申请证书,文件保存在 /etc/letsencrypt/live/example.com/。

第四步:检查 HTTPS 配置

Certbot 改完后,server 配置里应该引用 fullchain.pem 和 privkey.pem,并且 HTTP 会跳转到 HTTPS。自己手写配置可以参考:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;    # Nginx 1.25.1 及以上;更老的版本改成 "listen 443 ssl http2;"
    server_name example.com www.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;
    ssl_session_timeout 1d;

    root /var/www/example.com;
    index index.html;
}

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

不要加 ssl_stapling 和 ssl_stapling_verify,Let's Encrypt 证书里已经没有 OCSP 地址了。加密套件可以用 TLS 配置生成器 按兼容性需求生成。改完后重载:

sudo nginx -t && sudo systemctl reload nginx

验证

配置正确时,证书颁发者是 Let's Encrypt,curl -I http://example.com 返回 301,Location 指向 https://。从外部检查线上证书:打开 SSL 证书检查,或在任意终端运行:

curl ssl.sh/example.com

在服务器上确认 Certbot 管理的证书和 Nginx 实际返回的证书:

sudo certbot certificates
curl -sI https://example.com | head -n 1
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

自动续期

snap 版已经配置好续期:systemd 定时器 snap.certbot.renew.timer 每天运行两次 certbot renew。Certbot 4.1 及以上会查询 ARI(ACME 续期信息),按 Let's Encrypt 建议的时间续期;没有 ARI 时在剩余三分之一有效期时续期。确认定时器并做一次续期演练:

systemctl list-timers | grep certbot
sudo certbot renew --dry-run

用 --nginx 申请的证书续期后会自动重载 Nginx。用 certonly --webroot 或 --standalone 申请的,要加部署钩子让 Nginx 加载新证书:

sudo certbot reconfigure --cert-name example.com --deploy-hook "systemctl reload nginx"

pip 安装的没有定时器,需要按官方说明加 cron。钩子的详细用法见 Certbot 续期钩子。Let's Encrypt 默认证书 2027 年 2 月 10 日改为 64 天、2028 年 2 月 16 日改为 45 天,只要定时器在跑就不用改任何配置。Let's Encrypt 不再发提醒邮件,建议把域名加到 ssl.sh 监控(开发中) 兜底。

常见问题排查

大部分失败出在解析、端口和 server 配置上。

  • Timeout during connect 或 Connection refused:80 端口不通(安全组没放行、运营商封端口、未备案被拦截)或解析不对,见 certbot 连接超时。端口实在打不开就改用 DNS-01 验证。
  • Could not automatically find a matching server block:server_name 里没写对应域名,补上后重新运行。
  • too many certificates already issued:测试时触发了频率限制,测试请用 --dry-run 或 --test-cert(测试环境),见 Let's Encrypt 频率限制。
  • CAA record prevents issuance:域名的 CAA 记录没有允许 letsencrypt.org,见 CAA 记录阻止签发。
  • 重载 Nginx 报 key values mismatch:证书和私钥不是一对,见 nginx key values mismatch。
  • 访问 www 报 NET::ERR_CERT_COMMON_NAME_INVALID:证书里没有这个域名,带上所有 -d 重新运行并选择 Expand,见 NET::ERR_CERT_COMMON_NAME_INVALID。
  • 浏览器正常但 curl、小程序或 App 报错:Nginx 用了 cert.pem,见 缺少中间证书。

常见问题

Nginx 里该用 cert.pem 还是 fullchain.pem?

用 fullchain.pem。它包含你的证书和 Let's Encrypt 的中间证书;cert.pem 只有站点证书,部分浏览器因为缓存了中间证书能打开,但 curl、Java、安卓 App 和微信小程序会报证书链不完整。

还需要配置 ssl_stapling 吗?

Let's Encrypt 证书不需要。Let's Encrypt 2025 年 5 月起签发的证书已不含 OCSP 地址,8 月关闭了 OCSP 服务。开着 ssl_stapling on; 只会让 Nginx 在日志里警告证书没有 OCSP 地址,删掉相关配置即可。

服务器 80 端口不通或者域名没备案,还能用 certbot --nginx 申请证书吗?

不能。certbot --nginx 用的是 HTTP-01 验证,Let's Encrypt 必须能从公网访问你服务器的 80 端口。80 端口被封、域名未备案无法开放访问时,改用 DNS-01 验证,见 acme.sh + 阿里云 DNS/DNSPod 申请通配符证书。

能用 certbot --nginx 申请通配符证书吗?

不能。*.example.com 这类通配符证书只能用 DNS-01 验证。国内 DNS 推荐用 acme.sh 的 DNS API,域名在 Cloudflare 的可以用 Certbot Cloudflare DNS 插件。

怎么改用 45 天的 tlsserver 证书?

Certbot 4.0 及以上支持 --preferred-profile tlsserver(或 --required-profile),4.1 起会把选择保存到续期配置里。切换前先看 Let's Encrypt 证书配置文件,保证续期至少每天检查一次。

资料来源

  1. Certbot instructions: Nginx on Linux (snap)
  2. Certbot User Guide
  3. nginx: Configuring HTTPS servers
  4. nginx: Module ngx_http_ssl_module
  5. Let's Encrypt: Ending OCSP Support in 2025
  6. Let's Encrypt: Decreasing Certificate Lifetimes to 45 Days