Certbot申请泛域名证书与续期

前两天朋友向我问起泛域名证书申请的事,他说在面板上一直申请不了,我印象中以前自己使用面板时申请证书还是很方便的。就是试过几次因为面板版本升级导致无法续期证书的情况,因此只有稳定性问题,不存在无法申请的问题。

借这次帮朋友解决证书问题的机会自己也做了个详细的记录。

安装

因为域名使用了 Cloudflare 的 DNS 解析,证书自动续期时要调用 Cloudflare 的 API,因此需要安装 Cloudflare 官方提供的插件1

使用 pip

如果你系统是使用 APT 包管理器,如 Debian, Ubuntu..

sudo apt update && sudo apt install python3 python3-venv libaugeas0

如果你系统是使用 RPM 包管理器,如 Fedora, CentOS..

sudo dnf install python3 augeas-libs

# 如果是旧系统的话
sudo yum install python3 augeas-libs

设置 python 虚拟环境,这一步非常有必要,这样子就不会破坏原系统上的 python 环境。

sudo python3 -m venv /opt/certbot/

更新虚拟环境上的 pip 包管理器

sudo /opt/certbot/bin/pip install --upgrade pip

安装 certbot 及 cloudflare 插件

sudo /opt/certbot/bin/pip install certbot certbot-dns-cloudflare

如果域名托管在阿里云

sudo /opt/certbot/bin/pip install certbot certbot-dns-aliyun

如果域名托管在腾讯云

sudo /opt/certbot/bin/pip install certbot git+https://github.com/tengattack/certbot-dns-dnspod.git

更多插件相关可查阅: https://eff-certbot.readthedocs.io/en/latest/using.html#dns-plugins

创建链接,让系统可直接使用 certbot 命令

sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot

至此,certbot 及相应的插件便安装完成了。

如要升级,可根据安装的插件来替换以下命令

sudo /opt/certbot/bin/pip install --upgrade certbot certbot-dns-cloudflare

若出现问题,可直接使用 sudo rm -rf /opt/certbot 来删除这个 python 虚拟环境,然后按上述步骤重新安装即可。

使用 snap

本人使用的安装方法,如果你同样使用 Ubuntu 这个系统的话,也可以尝试一下。我使用 snap 的原因有两点,沙盒运行和自动更新。总之,snap 的优缺点非常明显,在此不过多叙说,选择适合自己的。

# 安装 certbot
sudo snap install --classic certbot
# 创建链接
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# 信任插件
sudo snap set certbot trust-plugin-with-root=ok
# 安装插件
sudo snap install certbot-dns-cloudflare

使用 apt (不推荐)

使用 APT 包管理工具来安装 certbot 以及相应插件,并且域名托管在 Cloudflare 的话,必须使用 Cloudflare Global API Key 才能成功申请并自动续期泛域名证书。个人非常不建议这个选择,全局 API 密钥可能会产生安全问题。

sudo apt update && sudo apt install certbot python3-certbot-dns-cloudflare

申请证书

上述介绍了 Certbot 及其插件的三种安装方式,在使用旧版本时,如果使用 Cloudflare 来解析域名的话,需要注意安全问题,接下来继续完成未完成的工作。

创建配置文件

mkdir -p ~/.secrets/certbot && vim ~/.secrets/certbot/cloudflare.ini

添加以下内容

# Cloudflare API token used by Certbot
dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567

注:将内容上的令牌2修改成自己的

若你仍然坚持使用 APT 包管理工具来安装 certbot 及其插件,将 ~/.secrets/certbot/cloudflare.ini 替换成以下内容,使用全局 API 密钥3(慎重选择)

dns_cloudflare_email = "Cloudflare Email"
dns_cloudflare_api_key = Global API Key

如果域名托管在阿里云,创建 ~/.secrets/certbot/aliyun.ini 添加以下内容

dns_aliyun_access_key = 12345678
dns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef

查看阿里云 AccessKey: https://ram.console.aliyun.com/

如果域名托管在腾讯云,将 ~/.secrets/certbot/dnspod.ini 添加以下内容

dns_dnspod_api_id = 12345
dns_dnspod_api_token = 1234567890abcdef1234567890abcdef

查看腾讯云 API Token:https://www.dnspod.cn/console/user/security

设置安全权限

sudo chmod 0400 ~/.secrets/certbot/cloudflare.ini

申请指令

sudo certbot certonly --non-interactive --agree-tos --email i@iamlm.com --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini --dns-cloudflare-propagation-seconds 30 -d laomai.org,*.laomai.org

注:使用对应的配置文件

申请成功则如下显示

sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini --dns-cloudflare-propagation-seconds 30 -d laomai.org,*.laomai.org

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): i@iamlm.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must
agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
Account registered.
Requesting a certificate for laomai.org and *.laomai.org
Waiting 30 seconds for DNS changes to propagate

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/laomai.org/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/laomai.org/privkey.pem
This certificate expires on 2024-04-12.
These files will be updated when the certificate renews.

NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.
We were unable to subscribe you the EFF mailing list because your e-mail address appears to be invalid. You can try again later by visiting https://act.eff.org.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

配置证书

以 Nginx 为例,添加以下内容到相应站点的 Nginx 配置文件上。如:/etc/nginx/conf.d/laomai.org.conf

listen 443 ssl;
	ssl_certificate /etc/letsencrypt/live/laomai.org/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/laomai.org/privkey.pem;

测试 Nginx

sudo nginx -t

返回以下内容则表示配置正确

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

重启 Nginx

sudo nginx -s reload

自动续期

常用方法有两个,Crontab 或 Systemd.timer。

Crontab

查看 certbot 与 nginx 的完整路径

which certbot

which nginx

crontab -e 添加计划

35 19 * * * /usr/bin/certbot renew --quiet --agree-tos --post-hook "/usr/sbin/nginx -s reload" > /dev/null 2>&1

说明:

  • 因服务器时区关系我将触发时间设置成 35 19 * * *
  • --quiet 选项用于抑制 certbot 命令的输出,--post-hook 选项用于在证书续订后执行 /usr/sbin/nginx -s reload 命令来重新加载 Nginx 配置;
  • 如果想保留日志,可以用 >> /etc/letsencrypt/certbot.log 2>&1 替换 > /dev/null 2>&1,建议先行创建用来记录日志的文件,touch /etc/letsencrypt/certbot.log
  • >> /etc/letsencrypt/certbot.log 2>&1 将 certbot 命令的输出和错误消息都追加到 /etc/letsencrypt/certbot.log 日志文件中。如果使用 > 而不是 >>,则每次运行计划时,/etc/letsencrypt/certbot.log 日志文件都会被覆盖,从而导致以前的日志丢失;

Systemd.timer

创建文件:/etc/systemd/system/certbot.service

[Unit]
Description=certbot renew

[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --agree-tos --post-hook "/usr/sbin/nginx -s reload"

创建文件:/etc/systemd/system/certbot.timer

[Unit]
Description=Automatic renewal certificates

[Timer]
OnCalendar=19:35:00
RandomizedDelaySec=1h
Persistent=true

[Install]
WantedBy=timers.target

启用自动更新:

sudo systemctl enable --now certbot.timer

Systemd 扩展:

# 停止并删除
sudo systemctl stop certbot.timer
sudo systemctl disable certbot.timer
sudo systemctl stop certbot.service
sudo systemctl disable certbot.service
sudo rm /etc/systemd/system/certbot.timer
sudo rm /etc/systemd/system/certbot.service

# 重新读取
sudo systemctl daemon-reload

# 开始
sudo systemctl start certbot.service

# 查看状态与日志
sudo systemctl status certbot.service

journalctl -u certbot

# 查看timer列表
systemctl list-timers

Docker 部署

我个人偏向使用容器化来部署项目,比如说这个博客我就是使用 Nginx Proxy Manager 来进行代理管理,还有 Twikoo 评论,Umami 等等。但是为什么一开始我并没有介绍如何使用 Docker 来部署并申请证书呢?

主要原因有以下两点:

  1. 如果拥抱容器化,那么直接使用 Nginx Proxy Manager 来管理项目就好,Nginx Proxy Manager 提供了很好的证书申请与管理页面,更为直观,而且证书都是自动续期的。
  2. 使用 Docker 部署 Certbot 并申请证书,在设置自动续期上我没有搞懂如何利用勾子来触发宿主机的 Nginx 去重载配置。当然,如果暴力一点,每天运行自动续期命令时都让宿主机上的 Nginx 重载配置也是可行的。

利用 Docker 申请证书

docker run -it --rm --name certbot \
	-v "/root/.secrets/certbot/cloudflare.ini:/opt/certbot/cloudflare.ini" \
	-v "/etc/letsencrypt:/etc/letsencrypt" \
	-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
	-v "/var/log/letsencrypt:/var/log/letsencrypt" \
	certbot/dns-cloudflare certonly --non-interactive --agree-tos --email i@iamlm.com --dns-cloudflare --dns-cloudflare-credentials /opt/certbot/cloudflare.ini --dns-cloudflare-propagation-seconds 30 -d laomai.org,*.laomai.org

利用 Docker 续期证书

docker run -it --rm --name certbot \
	-v "/root/.secrets/certbot/cloudflare.ini:/opt/certbot/cloudflare.ini" \
	-v "/etc/letsencrypt:/etc/letsencrypt" \
	-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
	-v "/var/log/letsencrypt:/var/log/letsencrypt" \
	certbot/dns-cloudflare renew --non-interactive --agree-tos --email i@iamlm.com --dns-cloudflare --dns-cloudflare-credentials /opt/certbot/cloudflare.ini

添加自动续期计划

35 19 * * * docker run -it --rm --name certbot -v "/root/.secrets/certbot/cloudflare.ini:/opt/certbot/cloudflare.ini" -v "/etc/letsencrypt:/etc/letsencrypt" -v "/var/lib/letsencrypt:/var/lib/letsencrypt" -v "/var/log/letsencrypt:/var/log/letsencrypt" certbot/dns-cloudflare renew --non-interactive --agree-tos --email i@iamlm.com --dns-cloudflare --dns-cloudflare-credentials /opt/certbot/cloudflare.ini; nginx -s reload

最后

之前记录过一次在群晖上使用 acme.sh 来申请证书,与 certbot 相比,acme.sh 更加灵活一点。但是个人感觉 certbot 更加规范一些,当然,它俩的功能都是一样的。就看我们如何去使用了,用 certbot 申请的证书如果想要在面板上使用的话,只需在面板上修改 ssl_certificatessl_certificate_key 对应的路径即可。


Footnotes

  1. https://github.com/cloudflare/certbot-dns-cloudflare ;

  2. https://developers.cloudflare.com/fundamentals/api/get-started/create-token/

  3. https://developers.cloudflare.com/fundamentals/api/get-started/keys/