1 简介
Let’s Encrypt是一个旨在提升互联网安全、免费、自动化的证书颁发机构(CA),由互联网安全研究小组(ISRG)运营。它可以提供 90 天有效期的 TLS 证书,我们可以通过 Certbot 自动部署工具来实现自动化续期而达到免费长期使用,So, Let’s Encrypt!
Certbot是由 EFF (电子前哨基金会) 运营的实现 ACME (自动证书管理环境)协议的 TLS 自动部署工具,在这里可以查看在不同系统和环境下的安装命令。在使用Certbot前,建议仔细阅读Certbot文档 和 Let’s Encrypt 文档,其中对很多概念都有详细的讲解,也会解决很多你遇到的问题。以下简单记录常用的使用摘要。
2 使用摘要
2.1 申请证书
https://certbot.eff.org/docs/using.html#getting-certificates-and-choosing-plugins
申请证书时,Let’s Encrypt 需要验证你对网站的所有权,主要有通过访问指定文件和访问指定 dns 记录等方式,具体有以下 5 种:
- webroot:在网站指定目录下存放指定文件,以使 certbot 验证网站的所有权
- standalone: 仅申请证书
- nginx/apache: 申请证书并配置相应服务软件
- plugin:根据不同的 DNS 服务提供商集成的一键申请模型
- manual:可手动指定认证方式为 http 或 dns,http 即通过验证网站指定文件,dns 即通过验证 dns 的 txt 记录
需要注意的是,Let’s Encrypt每周对重复证书申请限制为 5 张,在学习证书申请时,可添加--test-cert
参数申请测试证书,限制为每周 3万张。
2.2 管理证书
使用以下命令列出本机的所有通过 certbot 申请的证书:
1 | $ certbot certificates |
--cert-name
可用于 run
, certonly
, certificates
, renew
, delete
等子命令,指定操作某一域名,如certbot certificates --cert-name example.com
2.2.1 续签证书
https://certbot.eff.org/docs/using.html#re-creating-and-updating-existing-certificates
certbot renew
可自动更新 30 天内到期的证书,否则跳过本次任务(可用--dry-run
测试证书是否可正常更新)- 续期前后可以使用钩子来完成一些动作,如
certbot renew --pre-hook "service nginx stop" --post-hook "service nginx start"
- 可以使用
--deploy-hook
来完成续期成功后的动作,如certbot renew --deploy-hook /path/to/deploy-hook-script
- 钩子脚本位于
/etc/letsencrypt/renewal-hooks/{pre,post,deploy}
目录下,将脚本放置在对应位置,即可自动执行 -q
可关闭续期期间的日志输出-n
或--noninteractive
可用于防止阻塞用户输入,在cron 命令运行时很有用- 证书签发后,certbot 会自动在
/etc/letsencrypt/renewal/CERTNAME
目录下创建一个更新配置文件,之后的更新便会依据该文件进行更新(修改/etc/letsencrypt
中的任何文件都可能导致 certbot 无法正常工作!!!)
2.2.2 证书存放位置
https://certbot.eff.org/docs/using.html#where-are-my-certificates
/etc/letsencrypt/archive
和/etc/letsencrypt/keys
包含了所有以前的密钥和证书,而/etc/letsencrypt/live
则是指向最新版的软链接- 如果需要复制申请后的证书,可使用命令
\cp -rfL /path/to/{fullchain.pem,privkey.pem} dir
复制
2.3 日志
- 存储于
/var/log/letsencrypt
,默认 1k 个日志文件,超过 1k 个后删除最旧的
3 Docker 安装
Docker 方式支持多个 DNS 服务商,我们此处以 Cloudflare 为例,来实现 TLS 证书的申请、续期、撤销等操作,相关文档如下:
3.1 安装 certbot
在这里根据自己的主机配置安装 certbot。
3.2 安装 Docker
按照文档安装即可,不过墙内主机会由于网络原因下载特别慢。
3.3 申请证书
由于 Let’s Encrypt 只提供域名验证型(DV)证书,因此我们需要通过完成 certbot 对域名的指定动作才能证明我们对域名的拥有权。在 docker 方式中,我们通过 cloudflare.ini 文件来填写 cloudflare 的信息,先创建 cloudflare.ini 文件
1 | $ mkdir -p /home/xinyu/certbot |
在这里设置好 key 后,将以下信息写入 cloudflare.ini
文件:
1 | # Cloudflare API credentials used by Certbot |
在这一步有个坑,就是我们使用 Cloudflare 的 Global API Key 可以正常申请证书,而使用 API Tokens 则会有以下错误提示:
1 | Error determining zone_id: 6003 Invalid request headers. Please confirm that you have supplied valid Cloudflare API credentials. (Did you copy your entire API token/key? To use Cloudflare tokens, you'll need the python package cloudflare> |
仔细阅读相关文档,发现其中有这样一段话
Cloudflare’s newer API Tokens can be restricted to specific domains and operations, and are therefore now the recommended authentication option.
However, due to some shortcomings in Cloudflare’s implementation of Tokens, Tokens created for Certbot currently require Zone:Zone:Read and Zone:DNS:Edit permissions for all zones in your account. While this is not ideal, your Token will still have fewer permission than the Global key, so it’s still worth doing. Hopefully Cloudflare will improve this in the future.
难道是因为我的 API Tokens 配置有问题?各种尝试下仍然是相同的错误提示,最后在 certbot 的源码中终于看到了这样一段代码:
大意是还有一种认证方式是dns_cloudflare_api_token
,于是将cloudflare.ini
内容修改为以下内容,结果果然可以了
1 | # Cloudflare API credentials used by Certbot |
1 | sudo docker run -it --rm --name certbot \ |
参数说明:
--dns-cloudflare-propagation-seconds
可以根据自己的 DNS 解析时间调整;- Let’s Encrypt 每周对重复证书申请限制为 5 张,
--test-cert
参数调用测试证书,限制为每周 3 万张; - 如果不申请泛解析域名,可以去掉
--server https://acme-v02.api.letsencrypt.org/directory
。
3.4 查看证书
通过命令certbot certificates
可以查看我们主机上所有通过 certbot 申请的证书
3.5 续期证书
3.5.1 手动续期
要续期证书,可以将申请证书的命令再执行一次,在交互中选择续期选项,但为了自动化续期,我们可以通过以下命令实现一键续期:
1 | sudo docker run -it --rm --name certbot \ |
参数说明:
--dry-run
是续期测试命令,certbot 只会对30天内过期的证书进行续期,该命令可以测试有效期大于30天的证书是否可以正常续期。--cert-name
用于对指定证书续期,填写certbot certificates
中的Certificate Name
即可,无此参数默认对所有证书进行续期
如果在创建或者续期证书期间遇到以下错误,请适当调整--dns-cloudflare-propagation-seconds
参数,该错误的更多信息可以查看During secondary validation: Incorrect TXT record
1 | IMPORTANT NOTES: |
3.5.2 自动续期
手动操作太原始了,我们通过定时脚本的方式来自动完成该重复操作。
首先,我们创建一个用于续期的容器,我们每次需要续期的时候,只需要执行docker start certbot-renewal
启动容器即可
1 | $ docker run --name certbot-renewal \ |
如果要在容器中执行脚本,一定要查看容器 Linux 版本,Alpine 版本由于精简而经常用做制作容器,该版本中需要注意的是:
- shell 是 sh ,而不是 bash
- 有 wget,而没有 curl
- 不自持类似
cp /path/to/{file1,file2} dir
的多文件复制命令
接下来,我们需要一个 shell 脚本来处理续期的操作和通知
1 |
|
根据 Certbot 的续签文档,其中提供了基于续签前的
--pre-hook
,续签后的--post-hook
,续签成功的--deploy-hook
,可以充分利用钩子实现一些自动化的东西。
有了执行脚本之后,我们就需要设置下定时器了,我们采用 systemd 的定时功能,而不是传统的 crond。关于 systemd 的定时功能,可以查看Systemd 定时器教程 和 Linux 定时任务 crontab 和 Systemd Timer。
我们简单学习一下,就明白了 systemd 的定时也是比较简单的,我们只需要在/usr/lib/systemd/system
目录下创建.service
和.timer
文件即可,service 中包含了我们所需要执行的脚本, timer 中包含了我们的计划任务。
cert-renewal.service
文件内容为
1 | [Unit] |
cert-renewal.timer
文件内容为
1 | [Unit] |
现在万事俱备,只欠东风了。配置好定时器之后,我们依次执行以下命令:
systemctl daemon-reload
重载配置文件,查看服务状态systemctl status cert-renewal.timer
1 | ● cert-renewal.timer - cert-renewal |
此时,定时任务尚未激活,并且没有设置为开机自启,我们先执行systemctl enable cert-renewal.timer
设置为开机自启
1 | ● cert-renewal.timer - cert-renewal |
再激活任务systemctl start cert-renewal.timer
1 | ● cert-renewal.timer - cert-renewal |
虽然现在任务已经激活,但我们看到Trigger: n/a
,这表明任务并不能按照预期来定时执行,这是因为我们的任务执行时间是相对时间,因此需要手动执行一次任务systemctl start cert-renewal.service
,如果手动执行任务后仍没有出现下述状态,可以尝试systemctl restart cert-renewal.timer
1 | ● cert-renewal.timer - cert-renewal |
至此,我们我定时任务就设置完成了,用systemctl list-timers --all
来查看下所有的 systemd 的定时任务,之后每次修改定时任务后,只需重载配置文件即可。
如果设置定时任务后没有最近的执行时间以及下次执行时间,可以参照该视频处理
如果需要移除定时任务,依次执行:
systemctl disable test.timer
systemctl stop test.timer
sudo rm /usr/lib/systemd/system/example.*
systemctl daemon-reload
systemctl list-timers --all
3.6 吊销证书
1 | $ sudo certbot revoke --test-cert --cert-path /etc/letsencrypt/live/example.com/cert.pem |
参数说明:
- 由于我们申请的是测试证书,因此在吊销证书时同样需要用
--test-cert
指明吊销测试证书
3.7 更新证书域名
如果想将example.com
和*.example.com
更新为test.example.com
和www.example.com
,执行以下命令即可:
1 | $ certbot certonly --cert-name example.com \ |