概述
Certbot 是一个 ACME (Automated Certificate Management Environment,自动证书管理环境) 客户端。他可以申请、部署、续约和撤销 HTTPS 证书。
Certbot 通常用于申请 Let's Encrypt 证书。他支持以下验证方式:
standalonewebroot- Nginx 插件
- Apache 插件
- DNS 插件
- 手动 DNS 验证
本文以 Debian 系统为例,介绍 Certbot 的安装、申请、续约和自动化管理方法。
前置条件
开始申请证书前,需要确认以下条件:
- 域名的
A记录已指向服务器的公网 IPv4 地址。 - 域名存在
AAAA记录时,该记录必须指向正确的 IPv6 地址。 - HTTP 验证需要外部网络访问服务器的 TCP 80 端口。
- 防火墙和云服务安全组必须允许 TCP 80 和 TCP 443。
- 当前用户必须拥有
sudo权限。
可以使用以下命令检查 DNS 解析:
dig +short A example.com
dig +short AAAA example.com
安装 Certbot
安装基础组件
更新 Debian 软件包索引:
sudo apt update
安装 Certbot:
sudo apt install certbot
检查安装结果:
certbot --version
输出会包含当前安装的 Certbot 版本。
安装 Web 服务插件
使用 Nginx 时,安装 Nginx 插件:
sudo apt install python3-certbot-nginx
使用 Apache 时,安装 Apache 插件:
sudo apt install python3-certbot-apache
查看已经安装的 Certbot 插件:
sudo certbot plugins
申请 HTTPS 证书
使用 standalone 模式
standalone 模式会启动一个临时 HTTP 服务。该服务默认监听 TCP 80 端口。
申请单个域名证书:
sudo certbot certonly \
--standalone \
-d example.com
申请包含多个域名的证书:
sudo certbot certonly \
--standalone \
-d example.com \
-d www.example.com
该模式不会修改 Nginx 或 Apache 配置。申请成功后,需要手动配置 Web 服务。
使用该模式前,需要确认 TCP 80 端口处于空闲状态:
sudo ss -ltnp | grep ':80'
Nginx、Apache 或 Docker 容器可能占用该端口。
使用 webroot 模式
webroot 模式通过现有 Web 服务提供验证文件。他不需要停止 Nginx 或 Apache。
指定网站根目录并申请证书:
sudo certbot certonly \
--webroot \
-w /var/www/html \
-d example.com
外部网络必须能够访问 /.well-known/acme-challenge/ 路径。
使用 Nginx 插件
Nginx 插件可以申请证书,并自动修改 Nginx 配置:
sudo certbot --nginx \
-d example.com \
-d www.example.com
使用前需要安装 python3-certbot-nginx,并确保 Nginx 配置检查通过。
申请通配符证书
通配符证书必须使用 DNS 验证:
sudo certbot certonly \
--manual \
--preferred-challenges dns \
-d example.com \
-d '*.example.com'
Certbot 会要求用户创建 DNS TXT 记录。手动 DNS 验证不适合无人值守续约。
配置和验证证书
配置 Nginx
Certbot 默认将证书保存在以下目录:
/etc/letsencrypt/live/example.com/
Nginx 通常使用以下两个文件:
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
完整的 HTTPS 配置示例:
server {
listen 443 ssl;
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;
root /var/www/html;
}
检查并重载 Nginx:
sudo nginx -t
sudo systemctl reload nginx
不要将 privkey.pem 提交到 Git 仓库,也不要向其他用户开放读取权限。
验证证书
查看证书主题、签发机构和有效期:
sudo openssl x509 \
-in /etc/letsencrypt/live/example.com/cert.pem \
-noout \
-subject \
-issuer \
-dates
测试 HTTPS 连接:
curl -I https://example.com
检查 Nginx 配置:
sudo nginx -t
查看证书状态
查看全部证书
列出 Certbot 管理的证书:
sudo certbot certificates
示例输出:
Certificate Name: example.com
Domains: example.com www.example.com
Expiry Date: 2026-09-20 08:00:00+00:00
Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem
Certificate Name 是 Certbot 内部使用的证书名称。续约、撤销和删除证书时,可以通过 --cert-name 指定该名称。
查看证书目录
Certbot 的常用目录如下:
| 目录 | 用途 |
|---|---|
/etc/letsencrypt/live/ |
当前有效证书的软链接 |
/etc/letsencrypt/archive/ |
证书的历史版本 |
/etc/letsencrypt/renewal/ |
每张证书的续约配置 |
/etc/letsencrypt/renewal-hooks/ |
自动续约 Hook 脚本 |
/var/log/letsencrypt/ |
Certbot 日志 |
/var/lib/letsencrypt/ |
Certbot 工作数据 |
Web 服务应引用 /etc/letsencrypt/live/ 中的文件。
不要直接修改 live 或 archive 目录中的文件。
续约证书
测试续约
使用 Let's Encrypt 测试环境模拟续约:
sudo certbot renew --dry-run
测试成功时,会出现类似输出:
Congratulations, all simulated renewals succeeded
--dry-run 不会替换当前使用的正式证书。
执行续约
检查全部证书并续约符合条件的证书:
sudo certbot renew
Certbot 4.0.0 及以上版本会根据证书总有效期计算续约时间。
当证书剩余有效期少于总有效期的三分之一时,Certbot 会尝试续约。有效期不超过 10 天的证书使用二分之一作为阈值。
certbot renew 可以频繁执行。尚未进入续约期的证书会被跳过。
续约指定证书
只检查指定证书:
sudo certbot renew \
--cert-name example.com
强制续约指定证书:
sudo certbot renew \
--cert-name example.com \
--force-renewal
强制续约会申请新的正式证书。频繁执行可能触发证书颁发机构的速率限制。
Certbot 2.3.0 及以上版本可以使用 reconfigure 修改续约参数:
sudo certbot reconfigure \
--cert-name example.com \
--webroot-path /srv/www/example.com
Certbot 会先通过测试环境验证新配置。验证成功后,新配置会用于后续续约。
不建议直接编辑以下文件:
/etc/letsencrypt/renewal/example.com.conf
错误配置可能导致自动续约失败。
使用 Hook
Hook 类型
Hook (钩子) 可以在续约流程的不同阶段执行命令。
| Hook | 执行时间 | 常见用途 |
|---|---|---|
pre-hook |
开始续约尝试前 | 停止占用 TCP 80 的服务 |
post-hook |
完成续约尝试后 | 恢复此前停止的服务 |
deploy-hook |
证书成功签发或续约后 | 重载 Web 服务或部署证书 |
pre-hook 和 post-hook 只会在 Certbot 实际尝试续约时执行。
post-hook 不代表续约成功。需要在成功后执行的操作,应使用 deploy-hook。
使用命令行 Hook
standalone 模式需要释放 TCP 80 端口时,可以停止并恢复 Nginx:
sudo certbot renew \
--pre-hook "systemctl stop nginx" \
--post-hook "systemctl start nginx"
如果 Nginx 由 Docker Compose 管理,可以执行:
sudo certbot renew \
--pre-hook "docker compose -f /srv/web/compose.yaml stop nginx" \
--post-hook "docker compose -f /srv/web/compose.yaml start nginx"
docker compose stop nginx 会停止现有容器,但不会删除容器。
docker compose start nginx 会重新启动该容器。
定时任务的工作目录并不固定。因此,Hook 中应通过 -f 指定 Compose 文件的绝对路径。
证书成功续约后,可以重载 Nginx:
sudo certbot renew \
--deploy-hook "systemctl reload nginx"
使用 Hook 脚本目录
Certbot 会自动执行以下目录中的可执行文件:
/etc/letsencrypt/renewal-hooks/pre/
/etc/letsencrypt/renewal-hooks/deploy/
/etc/letsencrypt/renewal-hooks/post/
Hook 脚本统一使用 .sh 后缀。该后缀可以明确表示文件类型,也便于编辑器识别 Shell 语法。
脚本名称中的 10- 和 90- 用于控制执行顺序。Certbot 会按照文件名的字节顺序,执行同一个 Hook 目录中的脚本。
例如,以下脚本的执行顺序为:
10-stop-nginx.sh
20-stop-other-service.sh
90-write-log.sh
pre、deploy 和 post 是相互独立的目录。文件名排序只影响同一个目录中的执行顺序。
创建 standalone 模式的 Docker Compose 停止脚本:
sudo nano \
/etc/letsencrypt/renewal-hooks/pre/10-stop-nginx.sh
写入以下内容:
#!/bin/sh
set -eu
/usr/bin/docker compose \
-f /srv/web/compose.yaml \
stop nginx
创建恢复脚本:
sudo nano \
/etc/letsencrypt/renewal-hooks/post/90-start-nginx.sh
写入以下内容:
#!/bin/sh
set -eu
/usr/bin/docker compose \
-f /srv/web/compose.yaml \
start nginx
授予脚本执行权限:
sudo chmod +x \
/etc/letsencrypt/renewal-hooks/pre/10-stop-nginx.sh \
/etc/letsencrypt/renewal-hooks/post/90-start-nginx.sh
检查脚本权限:
sudo ls -l \
/etc/letsencrypt/renewal-hooks/pre/ \
/etc/letsencrypt/renewal-hooks/post/
确认 Docker 的实际路径:
command -v docker
如果输出路径不是 /usr/bin/docker,需要同步修改脚本。
测试 deploy-hook
普通 --dry-run 不会执行 deploy-hook。
测试续约和 deploy-hook:
sudo certbot renew \
--dry-run \
--run-deploy-hooks
测试成功时,Certbot 会使用当前正式证书执行 deploy-hook。他不会部署测试环境生成的临时证书。
管理自动续约
查看定时器状态
通过 Debian 软件包安装 Certbot 后,系统通常会创建 systemd 定时器。
查看定时器状态:
sudo systemctl status certbot.timer
查看下次执行时间:
sudo systemctl list-timers --all | grep certbot
启用并立即启动定时器:
sudo systemctl enable --now certbot.timer
正常运行时,状态通常为:
Active: active (waiting)
waiting 表示定时器正在等待下一次触发。
定时器会触发以下服务:
certbot.service
certbot.service 通常是一次性任务。任务执行完成后,显示 inactive (dead) 属于正常情况。
查看续约日志
查看 certbot.service 日志:
sudo journalctl \
--unit certbot.service \
--lines 50 \
--no-pager
查看最近一次启动后的日志:
sudo journalctl \
--unit certbot.service \
--boot \
--no-pager
查看 Certbot 文件日志:
sudo tail -n 100 \
/var/log/letsencrypt/letsencrypt.log
实时查看日志:
sudo tail -f \
/var/log/letsencrypt/letsencrypt.log
撤销和删除证书
撤销证书
撤销操作会通知证书颁发机构停止信任该证书。
按证书名称撤销:
sudo certbot revoke \
--cert-name example.com
也可以使用证书文件:
sudo certbot revoke \
--cert-path /etc/letsencrypt/live/example.com/cert.pem
私钥泄露时,可以指定撤销原因:
sudo certbot revoke \
--cert-name example.com \
--reason keycompromise
撤销后,如果保留续约配置,Certbot 仍可能再次尝试续约。无需继续使用时,应同时删除该证书。
删除证书
先查看证书名称:
sudo certbot certificates
删除证书前,需要移除 Nginx、Apache 或其他服务中的证书路径引用。
确认服务配置不再引用该证书后,执行:
sudo certbot delete \
--cert-name example.com
不要直接删除 /etc/letsencrypt/ 中的证书文件。
删除操作不会自动撤销证书。私钥未泄露时,通常不需要专门撤销。
常见问题
TCP 80 端口被占用
错误示例:
Could not bind TCP port 80 because it is already in use
查看端口占用情况:
sudo ss -ltnp | grep ':80'
也可以使用:
sudo lsof -iTCP:80 -sTCP:LISTEN
停止对应服务后,重新测试续约:
sudo certbot renew --dry-run
Docker Compose 服务占用端口
查看容器端口映射:
docker compose ps
查看全部运行中的容器:
docker ps \
--format 'table {{.Names}}\t{{.Ports}}'
停止指定 Compose 服务:
docker compose \
-f /srv/web/compose.yaml \
stop nginx
重新启动指定服务:
docker compose \
-f /srv/web/compose.yaml \
start nginx
start 只能启动已经存在且处于停止状态的容器。
如果容器已经通过 docker compose down 删除,需要重新创建:
docker compose \
-f /srv/web/compose.yaml \
up -d nginx
standalone 模式配合自动续约时,应配置 pre-hook 和 post-hook。否则,systemd 定时续约可能因端口冲突而失败。
域名验证失败
检查 IPv4 解析:
dig +short A example.com
检查 IPv6 解析:
dig +short AAAA example.com
检查 HTTP 是否可以访问:
curl -I http://example.com
如果存在错误的 AAAA 记录,Let's Encrypt 可能访问错误的 IPv6 地址。此时需要修正或删除该记录。
还需要检查以下项目:
- 云服务安全组
- Debian 防火墙
- 路由器端口转发
- 运营商端口限制
- HTTP 重定向规则
webroot 验证文件无法访问
创建测试文件:
sudo mkdir -p \
/var/www/html/.well-known/acme-challenge
echo 'certbot-test' | sudo tee \
/var/www/html/.well-known/acme-challenge/test
从外部访问:
curl \
http://example.com/.well-known/acme-challenge/test
预期输出:
certbot-test
测试完成后删除文件:
sudo rm \
/var/www/html/.well-known/acme-challenge/test
如果返回 403 或 404,需要检查 Nginx 的 root、alias、try_files 和隐藏文件拦截规则。
查看详细错误日志:
sudo certbot renew --dry-run -v
总结
- Debian 可以通过 APT 安装 Certbot 及其 Web 服务插件。
- 已经运行 Nginx 的服务器,优先使用 Nginx 插件或
webroot模式。这两种方式通常不需要停止 Web 服务。 standalone模式适合没有 Web 服务的服务器。该模式也适合可以短暂停止反向代理的场景。- Docker 容器占用 TCP 80 时,可以使用 Hook 停止并恢复指定服务。Hook 应使用 Compose 文件的绝对路径。
- Hook 脚本应使用
.sh后缀,并通过数字前缀控制执行顺序。 - 完成配置后,应检查
certbot.timer,并执行测试:sudo certbot renew --dry-run - 只有测试成功,才能确认自动续约流程可以正常工作。
版权声明
本文为原创文章,作者保留版权。转载请保留本文完整内容,并以超链接形式注明作者及原文出处。
作者: 除除
原文: /6504.html
(完)