# Nginx 配置 Let's Encrypt 免费证书：Certbot 教程

> 用 snap 安装 Certbot，给 Nginx 申请 Let's Encrypt 免费 SSL 证书，配置 HTTP 跳转 HTTPS 并验证自动续期，适用 Ubuntu、Debian。

Source: https://ssl.sh/zh/guides/nginx-lets-encrypt-certbot/
Last updated: 2026-11-10

用 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 端口。

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

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

用宝塔面板管理网站的，直接看 [宝塔面板配置 SSL 证书](https://ssl.sh/zh/guides/bt-panel-ssl/)，不要再手动改宝塔生成的 Nginx 配置。

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

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

```nginx
# /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;
}
```

启用并检查配置：

```bash
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，避免两个版本冲突：

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

不能用 snap 时，官方也提供 pip + 虚拟环境的安装方式（官方称“尽力支持”）：

```bash
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：

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

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

```bash
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。自己手写配置可以参考：

```nginx
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 配置生成器](https://ssl.sh/zh/tools/tls-config-generator/) 按兼容性需求生成。改完后重载：

```bash
sudo nginx -t && sudo systemctl reload nginx
```

## 验证

配置正确时，证书颁发者是 Let's Encrypt，`curl -I http://example.com` 返回 `301`，`Location` 指向 `https://`。从外部检查线上证书：打开 [SSL 证书检查](https://ssl.sh/zh/tools/ssl-checker/)，或在任意终端运行：

```bash
curl ssl.sh/example.com
```

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

```bash
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 时在剩余三分之一有效期时续期。确认定时器并做一次续期演练：

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

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

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

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

## 常见问题排查

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

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