基于acme.sh配置SSL证书
前言
为了提高安全性,在部署网络服务的时候经常需要使用HTTPS,但是域名证书很多都是要收费的,而如果要使用免费的证书,就不可避免受到限制:单域名、时间短、配置麻烦……反复权衡,最终选择用一种麻烦的方式——使用acme.sh
从“ZeroSSL”申请并自动更新证书。
ACME简介
自动证书管理环境(英语:Automatic Certificate Management Environment,缩写ACME)是一种通信协议,用于证书颁发机构与其用户的Web服务器之间的自动化交互,允许以极低成本自动化部署公钥基础设施。该协议由互联网安全研究小组(ISRG)为Let’s Encrypt服务设计,已由专门的IETF工作组在RFC 8555中规范为一个互联网标准。
如果要基于ACME实现服务器证书的管理,还需要两个条件:
-
ACME服务提供商,也就是支持基于ACME的免费或低成本的证书服务,最为知名也是最容易找到资料的也就是前面提到的Let’s Encrypt,此外ZeroSSL、BuyPass等也比较流行,大家可以根据自己的偏好选择。
功能 LE Buypass ZeroSSL SSL.com Google Public CA 有效期 90 天 180 天 90 天 90 天 90 天 多域名 支持 支持,最多 5 个 支持 收费支持 支持 泛域名 支持 不支持 支持 收费支持 支持 Rate Limit 有 有 收费无 未知 有 GUI 管理 否 否 有 有 无 ECC 证书链 否 否 有 未知 无 客户支持 社区 收费 收费 收费 收费 -
ACME客户端,需要安装在我们自己的服务器上,向ACME服务提供商发起请求,对使用ACEME协议的证书进行管理,ACME客户端也有许多,例如Let’s Encrypt比较流行的Certbot等,对于ZeroSSL 可以使用"acme.sh"(其默认采用ZeroSSL)。
客户端 类型 组织和/或主要赞助商 操作系统 开源 商业使用 acme.sh shell脚本 Neil Pang,ZeroSSL(apilayer) Linux, macOS 是 否 Caddy 网络服务器 Matt Holt,ArdanLabs,ZeroSSL(apilayer) Linux、macOS、Windows 是 是 Certbot python脚本 互联网安全研究小组 Linux、macOS、Windows 是 否 Certify The Web 图形界面和后台服务 Webprofusion Windows、Linux 是 是 win-acme 命令行 Wouter Tinus Windows 是 否
在接下来的内容里,我选择了ZeroSSL和acme.sh。
acme.sh基本用法
安装acme.sh
acme.sh 是一个集成了 ACME 客户端协议的 Bash 脚本,可以直接网络安装:
1 | curl https://get.acme.sh | sh -s [email protected] |
如果网络有问题,可以下载到本地后安装:
1 | git clone https://github.com/acmesh-official/acme.sh.git |
请注意替换 [email protected]
为你自己的邮箱,避免无法收到上游证书的邮件通知。
安装完成后重新加载 Bash:
1 | source ~/.bashrc |
然后也可以开启自动更新:
1 | acme.sh --upgrade --auto-upgrade |
选择默认CA
目前 acme.sh 支持四个正式环境 CA,分别是 Let’s Encrypt、Buypass、ZeroSSL 和 SSL.com,默认使用 ZeroSSL,如果需要更换可以使用如下命令:
1 | # 切换Let's Encrypt |
添加ZeroSSL 账号
如果已有 ZeroSSL 帐号,可以在后台控制面板拿到 API Key,然后执行如下命令
1 | apt install jq |
终端会输出如下内容
1 | { |
然后手工添加帐号
1 | acme.sh --register-account --server zerossl \ |
DNS验证签发证书
acme.sh 实现了 acme 协议支持的所有验证协议. 一般有两种方式验证: http 和 dns 验证。之所以选择使用dns验证,是因为dns 方式的真正强大之处在于可以使用域名解析商提供的 api 自动添加 txt 记录完成验证。
acme.sh 目前支持 cloudflare, DNSPod, cloudxns, godaddy 以及 ovh 等数十种解析商的自动集成,以DNSPod为例,先登录到DNSPod账号,生成ID和Token:
然后:
1 | export DP_Id="前面生成的ID" |
证书就会自动生成了. 这里给出的 api id 和 api key 会被自动记录下来, 将来你在使用 dnspod api 的时候, 就不需要再次指定了. 直接生成就好了:
1 | acme.sh --issue --dns dns_dp -d mydomain2.com |
安装证书
Nginx example:
1 | acme.sh --install-cert -d example.com \ |
(一个小提醒, 这里用的是 service nginx force-reload
, 不是 service nginx reload
, 据测试, reload
并不会重新加载证书, 所以用的 force-reload
)
Nginx 的配置 ssl_certificate
使用 /etc/nginx/ssl/fullchain.cer
,而非 /etc/nginx/ssl/<domain>.cer
,否则 SSL Labs 的测试会报 Chain issues Incomplete
错误。
--install-cert
命令可以携带很多参数, 来指定目标文件. 并且可以指定 reloadcmd, 当证书更新以后, reloadcmd会被自动调用,让服务器生效.
详细参数请参考: https://github.com/Neilpang/acme.sh#3-install-the-issued-cert-to-apachenginx-etc
值得注意的是, 这里指定的所有参数都会被自动记录下来, 并在将来证书自动更新以后, 被再次自动调用。
更新证书
目前证书在 60 天以后会自动更新, 你无需任何操作. 今后有可能会缩短这个时间, 不过都是自动,我们可以查看以下定时任务的具体内容:
1 | crontab -l |
更新 acme.sh
目前由于 acme 协议和 letsencrypt CA 都在频繁的更新, 因此 acme.sh 也经常更新以保持同步.
升级 acme.sh 到最新版 :
1 | acme.sh --upgrade |
如果你不想手动升级, 可以开启自动升级:
1 | acme.sh --upgrade --auto-upgrade |
之后, acme.sh 就会自动保持更新了.
你也可以随时关闭自动更新:
1 | acme.sh --upgrade --auto-upgrade 0 |
出错怎么办
如果出错, 请添加 debug log:
1 | acme.sh --issue ..... --debug |
或者:
1 | acme.sh --issue ..... --debug 2 |
番外:Certbot自动签发
网上有很多关于Certbot和Let’s Encrypt的资料,提到Certbot在使用DNS验证的时候,需要手动添加DNS验证记录。实际上Certbot也支持自动的DNS验证,但是需要通过插件来实现。官网列出了一些DNS验证插件,但是没有国内常用的阿里云和DNSPod:
Plugin | Auth | Inst | Notes |
---|---|---|---|
haproxy | Y | Y | Integration with the HAProxy load balancer |
s3front | Y | Y | Integration with Amazon CloudFront distribution of S3 buckets |
gandi | Y | N | Obtain certificates via the Gandi LiveDNS API |
varnish | Y | N | Obtain certificates via a Varnish server |
external-auth | Y | Y | A plugin for convenient scripting |
pritunl | N | Y | Install certificates in pritunl distributed OpenVPN servers |
proxmox | N | Y | Install certificates in Proxmox Virtualization servers |
dns-standalone | Y | N | Obtain certificates via an integrated DNS server |
dns-ispconfig | Y | N | DNS Authentication using ISPConfig as DNS server |
dns-clouddns | Y | N | DNS Authentication using CloudDNS API |
dns-lightsail | Y | N | DNS Authentication using Amazon Lightsail DNS API |
dns-inwx | Y | Y | DNS Authentication for INWX through the XML API |
dns-azure | Y | N | DNS Authentication using Azure DNS |
dns-godaddy | Y | N | DNS Authentication using Godaddy DNS |
njalla | Y | N | DNS Authentication for njalla |
DuckDNS | Y | N | DNS Authentication for DuckDNS |
Porkbun | Y | N | DNS Authentication for Porkbun |
Infomaniak | Y | N | DNS Authentication using Infomaniak Domains API |
解决的办法有两个:
- 使用第三方DNS验证插件,网上其实有四三方的阿里云和DNSPod插件:certbot-dns-aliyun 和 certbot-dns-dnpod;
- 使用Certbot辅助工具,certbot-letencrypt-wildcardcertificates-alydns-au,感兴趣的可以列的参考资料【6】、【7】。
小结
自动化签发、更新SSL证书其实并不是一个多么神秘的事情,只要有合适的服务商和API,我们自己完全也可以造轮子,当然如果有现成的,何乐而不用呢?
参考资料
- https://zh.wikipedia.org/wiki/自動憑證更新環境
- https://u.sb/acme-sh-ssl/
- https://zhuanlan.zhihu.com/p/75032510
- https://github.com/acmesh-official/acme.sh/wiki/说明
- https://blog.wayneshao.com/posts/46309.html
- https://github.com/ywdblog/certbot-letencrypt-wildcardcertificates-alydns-au
- https://blog.wayneshao.com/posts/46309.html
- https://eff-certbot.readthedocs.io/en/stable/using.html#manual
- https://absolutecommerce.co.uk/blog/auto-renew-letsencrypt-nginx-certbot