1. 引言
之前有两篇文章简单介绍了什么是 CA 以及 Openssl 的简单的操作,本篇介绍如何快速通过 acme.sh 这个开源项目,向 Let’s Encrypt 进行证书申请
协议方面,Let's Encrypt
用于自动注册证书颁发机构的质问-响应协议称为自动证书管理环境(ACME),它涉及对证书涵盖的域上的 Web 服务器的各种请求,基于所得到的响应是否与期望相匹配,确保了对域的登记者的控制(域验证)。
Let's Encrypt
在签发过程中,这种行为称之为会向签发者的挑战,让签发者证明其为被签发的域名的拥有者,除了本文介绍的在服务器上进行证书挑战,还有基于 DNS 方式的挑战等
2. 下载并安装 acme.sh
安装过程完成了下列内容,参考: https://github.com/Neilpang/acme.sh
- 创建和拷贝
acme.sh
到$HOME
目录: ~/.acme.sh/
(所有证书也会放这个目录下) - 创建一个 alias:
acme.sh=~/.acme.sh/acme.sh
- 创建了一个每天定时任务,按需重新签发需要更新的证书
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # 直接用git安装
git clone https://github.com/acmesh-official/acme.sh.git
cd ./acme.sh
# 指定你的邮箱(通知)
./acme.sh --install -m hold7habits@gmail.com
[Sun Jun 11 15:16:20 CST 2023] It is recommended to install socat first.
[Sun Jun 11 15:16:20 CST 2023] We use socat for standalone server if you use standalone mode.
[Sun Jun 11 15:16:20 CST 2023] If you don't use standalone mode, just ignore this warning.
[Sun Jun 11 15:16:20 CST 2023] Installing to /root/.acme.sh
[Sun Jun 11 15:16:20 CST 2023] Installed to /root/.acme.sh/acme.sh
[Sun Jun 11 15:16:20 CST 2023] Installing alias to '/root/.bashrc'
[Sun Jun 11 15:16:20 CST 2023] OK, Close and reopen your terminal to start using acme.sh
[Sun Jun 11 15:16:20 CST 2023] Installing alias to '/root/.cshrc'
[Sun Jun 11 15:16:20 CST 2023] Installing alias to '/root/.tcshrc'
[Sun Jun 11 15:16:20 CST 2023] Installing cron job
[Sun Jun 11 15:16:20 CST 2023] Good, bash is found, so change the shebang to use bash as preferred.
[Sun Jun 11 15:16:21 CST 2023] OK
# crontab -l
20 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
|
3. 用 acme.sh 签发阿里云域名 SSL 证书
3.1. 获取域名 KEY 和 SECRET
进入到阿里云官网生产 KEY 和 SECRET: https://ram.console.aliyun.com/users
3.2. 导出 KEY 和 SECRET 到环境变量
1
2
3
| # export KEY和SECRET到环境变量中
export Ali_Key="yours key"
export Ali_Secret="yours secret"
|
可以通过~/.acme.sh/dnsapi/dns_ali.sh
了解更多,后续签发证书后也会把该 KEY 和 SECRET 保存在~/.acme.sh/account.conf
文件中
3.3. 通 acme.sh 的 DNS 模式挑战,签发域名证书
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| # acme.sh --issue --dns dns_ali -d archstat.com -d *.archstat.com \
--cert-file /etc/nginx/ssl/archstat.com.cert \
--key-file /etc/nginx/ssl/archstat.com.key \
--fullchain-file /etc/nginx/ssl/archstat.com.fullchain \
--reloadcmd "systemctl restart nginx.service"
# 执行成功后,可以看到信息
...
Sat Mar 25 15:43:18 CST 2023] All success, let's return
[Sat Mar 25 15:43:18 CST 2023] Verifying: archstat.com
[Sat Mar 25 15:43:20 CST 2023] Processing, The CA is processing your order, please just wait. (1/30)
[Sat Mar 25 15:43:25 CST 2023] Success
[Sat Mar 25 15:43:25 CST 2023] Verifying: *.archstat.com
[Sat Mar 25 15:43:28 CST 2023] Processing, The CA is processing your order, please just wait. (1/30)
[Sat Mar 25 15:43:33 CST 2023] Success
[Sat Mar 25 15:43:33 CST 2023] Removing DNS records.
[Sat Mar 25 15:43:33 CST 2023] Removing txt: GTUoo9KJE4sKMS3oEIPMd5_pIrn_51nkHV5JV6BN_mo for domain: _acme-challenge.archstat.com
[Sat Mar 25 15:43:35 CST 2023] Removed: Success
[Sat Mar 25 15:43:35 CST 2023] Removing txt: iAhX2CH3CND4OC68mCSvAbqq5lfd8eWdirunLGrT_eM for domain: _acme-challenge.archstat.com
....
[Sat Mar 25 15:43:59 CST 2023] Your cert is in: /root/.acme.sh/archstat.com_ecc/archstat.com.cer
[Sat Mar 25 15:43:59 CST 2023] Your cert key is in: /root/.acme.sh/archstat.com_ecc/archstat.com.key
[Sat Mar 25 15:43:59 CST 2023] The intermediate CA cert is in: /root/.acme.sh/archstat.com_ecc/ca.cer
[Sat Mar 25 15:43:59 CST 2023] And the full chain certs is there: /root/.acme.sh/archstat.com_ecc/fullchain.cer
[Sat Mar 25 15:43:59 CST 2023] Installing cert to: /etc/nginx/ssl/archstat.com.cert
[Sat Mar 25 15:43:59 CST 2023] Installing key to: /etc/nginx/ssl/archstat.com.key
[Sat Mar 25 15:43:59 CST 2023] Installing full chain to: /etc/nginx/ssl/archstat.com.fullchain
[Sat Mar 25 15:43:59 CST 2023] Run reload cmd: systemctl restart nginx.service
|
acme.sh
相关参数说明:
1
2
3
4
5
6
7
8
9
10
| # acme.sh -h
--issue: 证书签发
--dns [dns_ali]: 使用DNS手动或API模式挑战,https://github.com/acmesh-official/acme.sh/wiki/dnsapi
-d,--domain <domain>: 指定要issue、renew、revoke的域名,支持通配符域名
--cert-file <file>: 在证书签发,重签后,证书Cert文件要拷贝的路径
--key-file <file>: 在证书签发,重签后,证书Key文件要拷贝的路径
--ca-file <file>: 在证书签发,重签后,中间CA证书文件要拷贝的路径
--fullchain-file <file>: 在证书签发,重签后,证书链要拷贝的文件
--days <ndays>: 指定在`--issue`重签间隔天数,默认是60天
--debug: 加入该参数,可以用于调试查看debug信息
|
签发成功后,后续 cron 定时任务会每天检测证书是否需要重签,重启成功后将重签证书拷贝到对应的 nginx 配置目录,这里是/etc/nginx/ssl
目录:
1
2
3
4
5
| # tree /etc/nginx/ssl
/etc/nginx/ssl
├── archstat.com.cert
├── archstat.com.fullchain
└── archstat.com.key
|
4. Nginx 服务的 SSL 配置参考
因为是通配符证书,考虑到证书可能会在多个 server 复用,抽离出来一个ssl_cert.conf
文件:
1
2
3
4
| # /etc/nginx/ssl_cert.conf
ssl_certificate ./ssl/archstat.com.fullchain;
ssl_certificate_key ./ssl/archstat.com.key;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
nginx 的 server 段部分 ssl 配置项:
1
2
3
4
5
6
7
8
9
10
11
| server {
listen 443 ssl;
server_name archstat.com;
# ssl config
include ssl_cert.conf;
location / {
return 200 "ok";
}
}
|
通过 curl 验证 TLS 是否生效:
1
2
3
4
5
6
7
8
9
10
11
12
13
| # curl -IvL https://archstat.com
* Rebuilt URL to: https://archstat.com/
...
* SSL connection using TLSv1.2 / ECDHE-ECDSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: CN=archstat.com
* start date: Mar 25 00:00:00 2023 GMT
* expire date: Jun 23 23:59:59 2023 GMT
* subjectAltName: host "archstat.com" matched cert's "archstat.com"
* issuer: C=AT; O=ZeroSSL; CN=ZeroSSL ECC Domain Secure Site CA
* SSL certificate verify ok
...
|
5. 通过 acme.sh 签发证书,验证域名归属(挑战)方式
参考: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert
常见包括 DNS、HTTP 模式:
- DNS API
- DNS manual mode:
- DNS alias mode
- Nginx mode
- Apache mode
5.1. Let’s Encrypt 进行 DNS 挑战,这个是操作最简易的,blog 自建的可以优先考虑这类
该 Mode 是基于 DNS API 认证方式(acme.sh 会动态的增加、删除 NX 解析,以证明域名是归你管理)
参考: https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode
具体云厂商 DNS API 认证挑战:https://github.com/acmesh-official/acme.sh/wiki/dnsapi
以阿里云为例:
进入到阿里云官网,设置访问 key,安全方面基于最小权限设定(建立组、给组分配仅可设定 dns 相关的权限,指定特定的账户的访问 key) https://ram.console.aliyun.com/users
将有限权限的 dns 账户,获取对应的 key 和秘钥,加入到.bashrc
中
export Ali_Key=“yours key”
export Ali_Secret=“yours secret”
签发多个通配符相关的证书、安装到指定目录、并设定重启:
1
2
3
| acme.sh --issue --dns dns_ali -d tkstorm.com -d *.tkstorm.com -d archstat.com -d *.archstat.com -d perf.plus -d lupguo.cool \
--fullchain-file /usr/local/nginx/conf/ssl/tkstorm.com.chained.cert --key-file /usr/local/nginx/conf/ssl/tkstorm.com.key \
--reloadcmd "service nginx reload"
|
5.2. Let’s Encrypt 进行 HTTP 接口挑战,GET /.well-known/acme-challenge
该 Mode 是基于 Token GET 请求验证证书归属后,进行证书签发
1
| acme.sh --issue -d go.archstat.com -w /data/ssl_challenge --debug
|
- 初始化一个 entry:
entry='"type":"http-01","url":"https://acme.zerossl.com/v2/DV90/chall/m4qQXcjcTJd3HiXHYj6ltw","status":"pending","token":"KF8l7T4FX0Rq8rU07No4T6mQ_ZsIBK1zhcDfQqBxez0"'
- 确定
/.well-known/acme-challenge
的 www 地址为/data/lets_challenge
- 生成一个 token 文件到 www 目录下
- 后 CA 会来检查对应的 token 内容,如果一致则挑战通过,进行域名的证书签发
比如请求: http://go.archstat.com/.well-known/acme-challenge/KF8l7T4FX0Rq8rU07No4T6mQ_ZsIBK1zhcDfQqBxez0'
配置 Nginx 服务器相关信息
- 创建一个独有可访问的 URI(
location ~ ^/.well-known/acme-challenge/
)提供给 Let’s Encrypt 检测,用于证书授权挑战(其他的还有诸如 dns 挑战等) - 创建一个专门用于证书申请的 server(参见下述配置),将挑战文件统一将认证的文件 root 指定到(
/data/lets_challenge
)
5.3. nginx 挑战服务配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| server {
listen 80 default_server;
# 1) 52explore.com (博客)
server_name 52explore.com www.52explore.com
# 2) archsatt.com (资料)
server_name archstat.com www.archstat.com;
# 3) tkstorm.com (博客)
server_name tkstorm.com www.tkstorm.com static.tkstorm.com;
# 4) psr100.cn (静态资源)
server_name psr100.cn www.psr100.cn;
server_name static.psr100.cn;
server_name pac.psr100.cn;
server_name git.psr100.cn;
server_name disqus.psr100.cn;
# 5) psr100.com
# server_name psr100.com www.psr100.com;
# 6) ioio.cool
# server_name ioio.cool www.ioio.cool;
# 7) heyman.cool
# server_name heyman.cool www.heyman.cool;
# let's encrypt域验证,我们把证书生成的内容存储到`/data/lets_challenge`中,让Let'S Encrypt进行查询认证
location ~ ^/.well-known/acme-challenge/ {
alias /data/lets_challenge;
try_files $uri =404;
}
# http请求转https
location / {
return 301 https://$host$request_uri;
}
}
|
针对所有域名 80 端口相关,提供给 Let’ Encrypt 的挑战,这个 nginx 服务,做了以下几个事情:
- 列出了所有需要进行证书签发的域名,进行统一管理授权和签发
- 将 acme.sh 把证书生成的内容存储到
/data/lets_challenge
中,设置一个 locaiton,让 Let’S Encrypt 进行查询认证 - 为了统一处理,后续请求这些域名的 http 协议统一转发到 https 协议处理(这块当然也可以在各自的 vhost 中设定)
6. 其他
6.1. 通过 acme.sh 代理,进行 ssl 证书签发挑战:(正式申请去掉—test、debug)
1
2
3
4
5
6
7
8
9
10
11
| # 签发支持多个域名的SAN证书
acme.sh --issue \
-d archstat.com -d www.archstat.com -d docker.archstat.com \
-d tkstorm.com -d www.tkstorm.com -d static.tkstorm.com \
-w /data/lets_challenge \
--test --debug
# 签发通配符证书,存储到/data/lets_challenge 下
acme.sh --issue -d archstat.com -d *.archstat.com \
-w /data/lets_challenge \
--test --debug
|
6.2. domain 认证挑战成功后,进行证书安装,acme.sh 将自动创建一个 cron 任务,并自动签署和更新证书
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| acme.sh --install-cert \
-d archstat.com -d www.archstat.com -d docker.archstat.com\
-d tkstorm.com -d www.tkstorm.com -d static.tkstorm.com \
--cert-file /usr/local/nginx/conf/ssl/arch_tkstorm.cert \
--key-file /usr/local/nginx/conf/ssl/arch_tkstorm.key \
--fullchain-file /usr/local/nginx/conf/ssl/arch_tkstorm.fullchain \
--reloadcmd "systemctl restart nginx.service"
acme.sh --install-cert \
-d psr100.cn -d www.psr100.cn -d static.psr100.cn -d pac.psr100.cn -d git.psr100.cn -d disqus.psr100.cn\
--cert-file /usr/local/nginx/conf/ssl/psr100.cert \
--key-file /usr/local/nginx/conf/ssl/psr100.key \
--fullchain-file /usr/local/nginx/conf/ssl/psr100.fullchain \
--reloadcmd "systemctl restart nginx.service"
# 签发通配符证书
acme.sh --install-cert -d archstat.com -d *.archstat.com \
--cert-file /etc/nginx/ssl/archstat.com.cer \
--key-file /etc/nginx/ssl/archstat.com.key \
--fullchain-file /etc/nginx/ssl/archstat.com.fullchain \
--reloadcmd "systemctl restart nginx.service"
|
6.3. 如果定时任务没有开启的话,开启定时任务自动更新签发证书
1
| acme.sh --install-cronjob
|
7. 参考