一个计算机技术爱好者与学习者

0%

使用Certbot申请泛域名证书

1. 需求描述

《Hexo启用https加密连接》一文中,我们在腾讯云申请了一个三级域名证书,然后给网站配置上了域名证书。

那如果我们有一百个域名,一个个申请域名证书就太麻烦了,这是我们就需要一个泛域名证书。怎么申请泛域名证书呢?
方案一:通过阿里云、腾讯云等云平台申请,但是需要付费,便宜的也要年费两千左右。
方案二:使用certbot申请泛域名证书,然后配置好自动续期。

因为想要省点钱,所以本文中我们就来研究学习一下方案二,给dnspod上的域名申请一个泛域名证书。

参考文档:

2. Certbot简介

为了在您的网站上启用 HTTPS,您需要从证书颁发机构(CA)获取证书(一种文件)。 Let’s Encrypt 是一个证书颁发机构(CA)。 要从 Let’s Encrypt 获取您网站域名的证书,您必须证明您对域名的实际控制权。 您可以在您的 Web 主机上运行使用 ACME 协议的软件来获取 Let’s Encrypt 证书。

而 Certbot,就是Let’s Encrypt推荐的 ACME 客户端,可以用来申请Let’s Encrypt颁发的域名证书。

Let’s Encrypt 的证书有效期为 90 天, 建议每 60 天自动续期一次证书。

Let’s Encrypt 对证书申请进行了限制,每个注册域名(顶级域名)可签发证书数量为每周50张。
证书续期遵守特殊规则:它们不计入每个注册域名的证书数量的限制,但它们受到每周最多 5 张重复证书的限制。

PS:与 Let’s Encrypt 类似的,还有一个 ZeroSSL

参考文档:

3. 安装配置思路

1、安装certbot(docker方式)
2、配置dns自动验证
3、申请泛域名
4、配置使用证书
5、配置证书自动续期

4. 安装Certbot

1、下载certbot镜像

1
docker pull certbot/certbot:v1.32.0

该镜像里包含python3.10.8,能够方便我们后续使用DNS自动验证脚本。

2、创建挂载目录

1
mkdir -p /etc/letsencrypt

3、测试运行

1
2
3
4
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot:v1.32.0 certonly

当我们运行certbot容器时,默认会执行certbot命令。
certonly是个参数,表示只申请证书,不会对nginx等web服务器进行自动配置。

5. 配置DNS自动验证

申请域名证书时,需要验证对域名的所有权,这个验证操作可以通过手动修改域名解析完成,也可以通过域名供应商提供的API自动完成。

本文中,对域名供应商API的自动操作,使用 certbot-letencrypt-wildcardcertificates-alydns-au

5.1. 申请DNS API密钥

要使用DNS API,需要先申请密钥。常见域名供应商获取 DNS API 密钥的入口:

5.2. 脚本配置

本节会对DNS自动验证脚本简单修改,适配certbot/certbot:v1.32.0镜像,觉得麻烦的同学可以直接跳到【脚本配置2.0】一节,使用修改好的脚本。

1、下载DNS自动验证脚本

1
2
3
4
mkdir -p /etc/letsencrypt/auth-hook
cd /etc/letsencrypt/auth-hook
git clone https://github.com/ywdblog/certbot-letencrypt-wildcardcertificates-alydns-au au
chmod 0777 au/au.sh

2、修改DNS API密钥
au.sh中,填入我们申请的DNS API密钥

3、指定使用sh运行脚本
容器中不存在bash,只有sh
所以au.sh头部,!#/bin/bash改为#/bin/sh

否则申请证书时会报错:
Hook ‘–manual-auth-hook’ for voidking.com reported error code 127
Hook ‘–manual-auth-hook’ for voidking.com ran with error output:
/bin/sh: /etc/letsencrypt/auth-hook/au/au.sh: not found

详情参考Certbot 无法运行挂钩脚本

4、修改python路径
容器中的python路径是/usr/local/bin/python
所以au.sh中,/usr/bin/python 改为 /usr/local/bin/python

否则申请证书时会报错:
Hook ‘–manual-auth-hook’ for voidking.com ran with error output:
/etc/letsencrypt/auth-hook/au/au.sh: line 112: /usr/bin/python: not found

5、添加根域名(可选)
domain.ini中,如果没有需要的根域名,需要自行添加

5.3. 脚本配置2.0

1、下载DNS自动验证脚本

1
2
3
4
mkdir -p /etc/letsencrypt/auth-hook
cd /etc/letsencrypt/auth-hook
git clone https://github.com/voidking/certbot-dns-au au
chmod 0777 au/au.sh

2、修改DNS API密钥
au.sh中,填入我们申请的DNS API密钥

3、添加根域名(可选)
domain.ini中,如果没有需要的根域名,需要自行添加

6. 申请泛域名证书

1、测试申请泛域名证书

1
2
3
4
5
6
7
8
9
10
11
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot:v1.32.0 certonly \
-d *.voidking.com \
-d voidking.com \
--manual \
--preferred-challenges dns \
--manual-auth-hook "/etc/letsencrypt/auth-hook/au/au.sh python txy add" \
--manual-cleanup-hook "/etc/letsencrypt/auth-hook/au/au.sh python txy clean" \
--dry-run

输出:

1
2
3
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Simulating a certificate request for *.voidking.com
The dry run was successful.

参数说明:

  • -d:要申请证书的域名。这里使用两个-d参数,使证书同时支持泛域名 *.voidking.com 和主域名 voidking.com
  • –manual-auth-hook:指定要添加dns记录的脚本,调用域名供应商提供的API添加要验证的dns记录
  • –manual-cleaup-hook:指定要删除dns记录的脚步,调用域名供应商提供的API删除要验证的dns记录
  • –dry-run:测试运行,并不真实申请证书

2、申请泛域名证书(去掉–dry-run)

1
2
3
4
5
6
7
8
9
10
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot:v1.32.0 certonly \
-d *.voidking.com \
-d voidking.com \
--manual \
--preferred-challenges dns \
--manual-auth-hook "/etc/letsencrypt/auth-hook/au/au.sh python txy add" \
--manual-cleanup-hook "/etc/letsencrypt/auth-hook/au/au.sh python txy clean"

根据提示,填写邮箱,同意协议等。

申请的证书文件,会被放到 /etc/letsencrypt/archive 路径中,同时 /etc/letsencrypt/live 路径中会创建软链,续期时会自动修改软链。
申请证书的相关参数,会被放到 /etc/letsencrypt/renewal 路径中

证书文件有四个,官方说明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
This directory contains your keys and certificates.

`privkey.pem` : the private key for your certificate.
`fullchain.pem`: the certificate file used in most server software.
`chain.pem` : used for OCSP stapling in Nginx >=1.3.7.
`cert.pem` : will break many server configurations, and should not be used
without reading further documentation (see link below).

WARNING: DO NOT MOVE OR RENAME THESE FILES!
Certbot expects these files to remain in this location in order
to function properly!

We recommend not moving these files. For more information, see the Certbot
User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates.

一般使用fullchain.pem和privkey.pem就可以了。如果开启了OCSP stapling,那么需要使用chain.pem。

7. 查看证书

1
2
3
4
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot:v1.32.0 certificates

8. 配置证书自动续期

因为申请证书的相关参数放到了 /etc/letsencrypt/renewal 路径中,所以我们可以通过一条命令实现续期。

8.1. 续期所有证书

1
2
3
4
5
6
7
8
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot:v1.32.0 renew \
--manual \
--preferred-challenges dns \
--manual-auth-hook "/etc/letsencrypt/auth-hook/au/au.sh python txy add" \
--manual-cleanup-hook "/etc/letsencrypt/auth-hook/au/au.sh python txy clean"

证书有效期小于 30 天的情况才会被 renew。

8.2. 续期指定证书

1
2
3
4
5
6
7
8
9
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot:v1.32.0 renew \
--cert-name voidking.com \
--manual \
--preferred-challenges dns \
--manual-auth-hook "/etc/letsencrypt/auth-hook/au/au.sh python txy add" \
--manual-cleanup-hook "/etc/letsencrypt/auth-hook/au/au.sh python txy clean"

8.3. 配置定时自动续期

1、证书续期脚本写入 cert-renew.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat <<EOF > /etc/letsencrypt/auth-hook/cert-renew.sh
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot:v1.32.0 renew --force-renewal \
--cert-name voidking.com \
--manual \
--preferred-challenges dns \
--manual-auth-hook "/etc/letsencrypt/auth-hook/au/au.sh python txy add" \
--manual-cleanup-hook "/etc/letsencrypt/auth-hook/au/au.sh python txy clean" \
>> /etc/letsencrypt/auth-hook/cert-renew.log
EOF

chmod a+x /etc/letsencrypt/auth-hook/cert-renew.sh

2、添加定时任务

1
crontab -e

添加每周定时执行:

1
0 0 * * 0 /bin/bash /etc/letsencrypt/auth-hook/cert-renew.sh

因为证书有效期小于 30 天的情况才会被 renew,所以 crontab 的周期可以配置为 1 天或 1 周。

9. 撤销证书

1
2
3
4
5
6
7
8
9
10
11
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot:v1.32.0 revoke \
--cert-name voidking.com
# or
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot:v1.32.0 revoke \
--cert-path /etc/letsencrypt/live/voidking.com/cert.pem

10. 使用证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;
listen 443 ssl;
server_name www.voidking.com;
charset utf-8;

ssl_certificate /etc/letsencrypt/live/voidking.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/voidking.com/privkey.pem;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/voidking.com/chain.pem;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!ADH:!EXPORT56:RC4+RSA:+MEDIUM;
ssl_prefer_server_ciphers on;
...
}

详情参考文档《Nginx入门篇》

11. dns-cloudflare

上文中的 certbot/certbot:v1.32.0 镜像,适用的域名供应商包括阿里云、腾讯云、华为云、Godaddy等,但是不适用于CloudFlare。

如果一个域名的DNS服务是由CloudFlare提供的,那么需要另外安装dns_cloudflare插件,才可以正常进行域名证书申请。
否则会报错:

1
Client with the currently selected authenticator does not support any combination of challenges that will satisfy the CA. You may need to use an authenticator plugin that can do challenges over DNS.

这里,我们可以选择使用安装好插件的镜像 certbot/dns-cloudflare:v2.8.0 ,使用方法如下:

1、申请一个cloudflare api-token

2、创建一个token配置文件 /etc/letsencrypt/cloudflare/cloudflare.ini
内容为:

1
dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567

3、申请域名证书

1
2
3
4
5
6
7
8
9
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/dns-cloudflare:v2.8.0 certonly \
-d *.voidking.com \
-d voidking.com \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare/cloudflare.ini \
--dns-cloudflare-propagation-seconds 60

12. 注意事项

老版本的操作系统或浏览器可能不支持 Let’s Encrypt 的根证书。报错:

1
2
错误: 无法验证 test.voidking.com 的由 “/C=US/O=Let's Encrypt/CN=R3” 颁发的证书:
颁发的证书已经过期。

这种情况下,需要更新系统或浏览器。

CentOS中:

1
yum install -y ca-certificates

Ubuntu中:

1
apt-get install -y ca-certificates

13. 后记

对于泛域名证书的配置,建议配置在内网最外层的网关入口处,这样方便统一配置。
例如:

1
2
3
Request -> Nginx(certificate)  -> Ingress
-> Nginx
-> Real Server

除了certbot,还有一款acme.sh也很好用,感兴趣的同学可以自行研究下。