certbot 申请 HTTPS 证书指南
certbot 是 Let's Encrypt 官方推荐的 ACME 客户端,用于自动申请、安装、续期免费 HTTPS 证书。它支持 Webroot、Standalone、DNS Challenge、Nginx 插件等多种验证方式,配合定时续期可以做到"一次配置,长期自动更新"。
本文记录了在 Nginx / 反代场景下用 certbot 申请证书的完整流程:安装、四种验证方式的选择、泛域名证书、自动续期与常见问题排查。
1. 工作原理:ACME 验证
Let's Encrypt 通过 ACME 协议验证你确实拥有域名后签发证书。验证方式核心分两类:
| 验证方式 | 原理 | 适用 |
|---|---|---|
| HTTP-01 | 在你的服务器 80 端口放一个随机 token 文件,CA 通过 http://域名/.well-known/acme-challenge/... 访问验证 | 有 80 端口、域名解析到本机 |
| DNS-01 | 在 DNS 添加一条 _acme-challenge TXT 记录,CA 查询 DNS 验证 | 泛域名(*.example.com)、无公网端口 |
certbot 会:
certbot 请求签发 → CA 下发验证令牌 → certbot 完成验证(放文件或加 DNS 记录)
→ CA 确认域名归属 → 签发证书 → certbot 写入 /etc/letsencrypt/ 并可选配置 Nginx
2. 安装 certbot
2.1 Debian / Ubuntu
sudo apt-get update
sudo apt-get install -y certbot
# 如使用 Nginx,推荐同时安装插件
sudo apt-get install -y python3-certbot-nginx
2.2 RHEL / CentOS / Rocky
sudo yum install -y certbot python3-certbot-nginx
2.3 Docker 方式(不影响宿主机)
docker run -it --rm \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/www:/var/www \
certbot/certbot certonly --webroot \
-w /var/www/html -d example.com
验证安装
certbot --version
certbot --help
3. 申请方式与选择
先决定用哪种方式,再执行对应命令。判断标准:80 端口是否可被外网访问?是否要泛域名?
| 方式 | 前提 | 优点 | 缺点 |
|---|---|---|---|
| Webroot | Web 服务已运行,域名解析到本机 | 不用停服务 | 需配置 webroot 目录 |
| Standalone | 80 端口空闲(无服务占用) | 最简单 | 验证期间 80 端口被 certbot 占用,需停其他服务 |
| Nginx 插件 | Nginx 已装且域名已配置 | 自动改 Nginx 配置 | 需装 python3-certbot-nginx |
| DNS Challenge | 域名 DNS 由支持 API 的服务商管理 | 支持泛域名、无需公网端口 | 需配置 DNS 服务商凭证,略复杂 |
3.1 Nginx 插件(最省事)
先确认 Nginx 配置里已有对应域名 server 块,然后:
# 自动申请证书并修改 Nginx 配置启用 HTTPS
sudo certbot --nginx -d example.com -d www.example.com
certbot 会:
- 验证域名;
- 生成证书;
- 自动修改
server_name对应 server 块,添加 SSL 配置与跳转。
验证 HTTPS:
curl -I https://example.com
# 应返回 200,证书有效
3.2 Webroot 方式
适合 Web 服务已运行、不想用 Nginx 插件自动改配置的场景:
sudo certbot certonly --webroot \
-w /var/www/html \
-d example.com \
-d www.example.com
-w 指定 Web 根目录(Nginx 里 root 指向的目录)。需要确保该目录可写,且 .well-known 不被 Nginx 拦截。
3.3 Standalone 方式
80 端口空闲时(如新服务器、尚无 Web 服务):
# 先停掉占用 80 的服务
sudo systemctl stop nginx
sudo certbot certonly --standalone -d example.com
# 申请完成后重启服务
sudo systemctl start nginx
3.4 DNS Challenge(泛域名)
要申请 *.example.com 泛域名证书,HTTP 验证不够,必须用 DNS-01:
# 手动 DNS 方式:certbot 给出需要添加的 TXT 记录,你手动添加后再继续
sudo certbot certonly \
--manual \
--preferred-challenges dns \
-d '*.example.com' -d example.com
按提示去 DNS 服务商添加 _acme-challenge.example.com 的 TXT 记录,确认后 certbot 完成签发。
# 自动 DNS 方式:使用服务商插件(如 cloudflare 插件),无需手动加记录
sudo apt-get install -y python3-certbot-dns-cloudflare
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d '*.example.com' -d example.com
# /etc/letsencrypt/cloudflare.ini(权限务必 600)
dns_cloudflare_api_token = your_api_token
4. 证书文件与 Nginx 配置
4.1 证书文件位置
/etc/letsencrypt/
├── live/
│ └── example.com/ # 软链接,指向当前有效证书
│ ├── fullchain.pem # 完整证书链(Nginx 用这个)
│ ├── privkey.pem # 私钥(Nginx 用这个)
│ └── cert.pem # 仅证书
├── archive/ # 历次证书归档
└── renewal/ # 续期配置
Nginx 配置示例:
server {
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;
# HTTP 强制跳转 HTTPS(可放在单独 server 块)
if ($scheme != "https") {
return 301 https://$host$request_uri;
}
}
4.2 查看证书信息
# 查看证书详情(颁发者、有效期、域名)
sudo certbot certificates
# 查看证书到期时间
echo | openssl s_client -servername example.com \
-connect example.com:443 2>/dev/null | openssl x509 -noout -dates
5. 自动续期
5.1 测试续期
# 模拟续期(不真正更新),确认配置无问题
sudo certbot renew --dry-run
看到类似 Congratulations, all simulated renewals succeeded 即正常。
5.2 配置自动续期
# 添加 systemd 定时器(推荐,certbot 包自带)
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer
# 或传统 cron 方式:每天两次尝试续期
echo "0 2 * * * root certbot renew --quiet --deploy-hook 'systemctl reload nginx'" | sudo tee /etc/cron.d/certbot
续期成功后需要让 Nginx 加载新证书,用 --deploy-hook 触发重载:
sudo certbot renew --deploy-hook "systemctl reload nginx"
5.3 验证续期成功
sudo certbot renew --dry-run
# 查看定时器状态
sudo systemctl status certbot.timer
journalctl -u certbot -n 20
6. 常见问题排查
| 现象 | 原因 / 处理 |
|---|---|
Port 80 already in use | Standalone 方式下 80 被 Nginx 占用 → 改用 --nginx / --webroot,或先停服务 |
Domain not found / 验证失败 | 域名 DNS 未解析到本机,或解析未生效 → dig example.com 确认 A 记录指向服务器 IP |
| 多次验证失败被限流 | Let's Encrypt 有速率限制 → 先确认配置无误再重试,不要反复快速请求 |
| 续期失败 | 证书目录不可写、Nginx 配置变化、DNS 记录变动 → 查看 /var/log/letsencrypt/letsencrypt.log |
CAA record forbids issuance | 域名有 CAA 记录但不允许 Let's Encrypt 签发 → 在 DNS 添加 0 issue "letsencrypt.org" |
| 泛域名证书续期卡在手动 DNS | --manual 方式需手动加 TXT → 改用服务商 DNS 插件实现自动续期 |
# 排查第一步:看日志
sudo tail -50 /var/log/letsencrypt/letsencrypt.log
CAA 记录(提前配置)
建议在域名 DNS 中添加 CAA 记录,只允许指定 CA 签发,降低被恶意签发风险:
example.com CAA 0 issue "letsencrypt.org"
7. 安全与运维建议
- 私钥与 API Token 权限:
/etc/letsencrypt/目录与 DNS API 凭证文件权限设为600/700,禁止组与其他用户读取; - 证书到期监控:配置监控(如 Prometheus
blackbox_exporter的 SSL 检查)或脚本检查到期时间,提前告警; - 不手动删 live 目录:续期依赖
live/软链接结构,手动清理会导致续期失败; - 多域名证书复用:
-d可叠加多个域名,但 Let's Encrypt 限制单证书 SAN 数量,超量可分多个证书; - 灾备:服务器重装后,证书可重新申请(有 90 天有效期兜底),不必备份私钥;但若用到不可重复验证的泛域名,建议备份
/etc/letsencrypt/。