使用ACME v2 API签发Let's Encrypt野卡SSL证书
去年年底,Let's Encrypt发布了其2018年的计划。其中,在“新功能”一节里提到在今年2月27日,ACME protocol API将会升级到v2版本,升级后用户将能够签发Wildcard证书,也就是所谓的“野卡”,不了解这是什么的话可以去看看wiki。能免费用上野卡,想想就很激动,然而几个月过去,我都快忘了这事的时候,今天Telegram群里突然有人说Let's Encrypt能签发野卡了。我赶紧跑去一看,发现官方在社区里发布了帖子,宣布ACME v2 API正式上线了。现在回去看去年的计划,发现实际上是跳票了。于是我今天就给自己手里的一个域名签了一张野卡证书,签发过程不麻烦,只要你用对了工具。
支持ACME v2 API的客户端
这次升级是个不小的升级,而野卡也只能使用v2版本的API签发,今天官方发的帖子里也说了,你需要一个支持ACME v2的客户端,官方有一个列表可供参考。
之前我使用的客户端一直是原Let's Encrypt官方客户端letsencrypt-auto
,现由EFF维护的客户端Certbot
。此客户端使用Python编写,之前在用的过程中虽然也没出过什么大问题,但说实话用起来总感觉不顺手。具体体现在以下几点:
- 依赖Python(虽然这个基本上是现在发行版的标配,但是有些精简的发行版,比如OpenWRT,就没有默认安装有Python)
- 使用Python virtualenv运行,每次运行时都要先等半天才能开始
- 会产生很多垃圾在
/root/
和其配置存储目录下 - 半自动,很多事比如配置定时自动更新证书都要用户自己做
当然,又不是不能用,crontab又不是不会写,但是今天我一运行傻了,提示不支持签发野卡,说好的已经上线了呢?我感觉是客户端版本太低了,但是我明明刚apt upgrade
过啊?于是我检查了一下版本,0.19.0
,而官方的列表显示至少要0.22.0
才支持ACME v2,然而软件包又没更新?那可能是发行版太旧了吧,然后我换了台Ubuntu 17.10的机器,更新软件包,一看certbot版本,0.21.0
。
这算什么鬼,我于是决定抛弃这个辣鸡,换其他的客户端看看。看了一下列表,有3个客户端是纯bash脚本实现的,说是也不需要其他依赖,我试了一下以后选择了个人感觉最好用的acme.sh。
使用 acme.sh 签发野卡证书
1. 安装
首先,安装 acme.sh。方法很简单,一行命令解决:
curl https://get.acme.sh | sh
或者
wget -O - https://get.acme.sh | sh
这会将acme.sh安装到你的$HOME
目录下。当然,你也可以根据文档进行自定义安装。
比如你可以指定安装位置到\etc\acme.sh
:
git clone https://github.com/Neilpang/acme.sh.git
cd acme.sh
./acme.sh --install --home /etc/acme.sh
安装后acme.sh
的脚本实际上保存在$install_dir/acme.sh
,比如我的就在/etc/acme.sh/acme.sh
。安装时会自动向你的~/.bashrc
添加alias,所以在安装完以后你需要退出bash重新进入,或者运行source .profile
使alias生效。
但是我日常用的shell是fish,而acme.sh并没有对fish做特殊配置,这时候就需要手动配置一下,不然运行的时候还要输入完整的路径。
tail -n 1 ~/.bashrc >> ~/.config/fish/config.fish
然后同样是重新进入fish,就能直接使用acme.sh
命令了。
2. 签发证书
签发野卡需要使用DNS模式,这需要你先去自己的DNS服务商获取API key和secret。
acme.sh已经支持的DNS提供商可以在这个列表里找到,如果你的提供商不在这个列表里面,你可以提交issue请求添加(但请注意作者没有义务为你添加),也可以更换到支持的服务商,或者你可以试试手动添加DNS记录。这里以我使用的GoDaddy为例:
首先去GoDaddy的开发者平台获取API key和secret。注意,如果是第一次添加key,打开页面后会只能先添加一个Test Key,而我们需要的是Production Key(辣鸡GoDaddy)。所以先添加一个Test Key,然后添加完我们需要的Production Key,记录好key和secret(关闭后不能再查看secret),最后再删除一开始添加的Test Key即可。
然后运行如下命令(如果你使用其他服务商,参数名会不一样,具体请参考上面提到的提供商列表):
export GD_Key="你的key"
export GD_Secret="你的secret"
然后就可以用DNS模式签发证书了,运行:
acme.sh --issue --dns dns_gd -d yourdomain.com -d *.yourdomain.com
不过为了更高的安全系数,我们可以在上面的命令后面加入-k
参数,签发一个ECC证书:
acme.sh --issue --dns dns_gd -d yourdomain.com -d *.yourdomain.com -k ec-384
这里-k
的参数可以是ec-256
(ECDSA P-256),ec-384
(ECDSA P-384)或者ec-521
(ECDSA P-521)(目前Let's Encrypt暂不支持P-521)
注意这里除了给子域名使用通配符,对于根域名也需要单独添加。因为所谓的通配符,只会匹配当前这一级子域名,所以不论是*.subdomain.yourdomain.com
这种二级子域名还是yourdomain.com
这个根域名都是没有匹配的,所以说野卡其实也没什么大不了。毕竟真正牛逼的是EV证书
你可能会担心上面export
的key和secret关了shell就消失了,其实不用担心,因为acme.sh已经自动帮你保存到了$install_dir/account.conf
里了,以后会自动使用这里面保存的参数。
等待大约2分30秒左右(等待DNS记录生效需要2分钟,其他模式会很快),签发好的证书就会被存放在acme.sh的安装目录下了,其路径也会在脚本运行的最后打印出来。
然后就可以修改nginx或Apache的配置,使用签发的野卡了,至于更新证书之类的事就完全不用管了,acme.sh已经帮你做好一切。由于使用了DNS模式,所以也不需要考虑先关闭nginx防止80端口被占用无法使用standalone模式验证的问题。
修改好nginx配置,重启nginx,打开浏览器,可以看到证书已经是刚才签发的野卡了,而且也是更安全的ECC证书了。