在前两年自己部署服务,刚接触到ssh证书的时候就看到过acme.sh,但是当时感觉好麻烦,而且阿里云、腾讯云都提供很多张一年的免费证书,所以一直懒得搞。不过随着阿里云在去年调整了免费证书的有效期,今年腾讯云也进行了调整,不得不着手研究自动化方案了,毕竟一年和三个月差距还是非常大的。

实际研究下来,发现acme这套方案确实是简单且强大,本篇文章来记录一下我会用到的几种使用acme.sh签发证书的方式。

本文几乎所有内容都来源于acme.sh的官方wiki

安装

尽管官方支持docker,但我觉得没必要,就用官方的一键脚本即可,非常简单

1
2
3
curl https://get.acme.sh | sh -s email=[email protected]
# 大概率可能需要代理,那么就需要加一个选项,下面是示例
# curl -x socks5h://127.0.0.1:1080 https://get.acme.sh | sh -s [email protected]

安装完成之后进入对应的目录,一般是cd ~/.acme.sh,此时ls应该可以看到有个acme.sh的文件,后面操作都在这个目录。

签发证书

DNS API

这里以阿里云为例,因为我有一个域名是托管在阿里云的,所以很常用这种方式。

获取AcessKey和SecretKey

  1. 登录阿里云控制台,跳转到RAM访问控制
  2. 创建一个用户,名称随意,备注一下云解析DNS
  3. 为用户添加权限,策略名称是AliyunDNSFullAccess,类型是系统策略,描述写的是管理云解析(DNS)的权限
  4. 完成后,为该用户创建AccessKey,注意把两个key存下来,关了对话框就看不到了。

证书签发

先设置环境变量,<key>对应刚才生成的AccessKey,<secret>对应SecretKey

1
2
export Ali_Key="<key>"
export Ali_Secret="<secret>"

然后最简单的方式就是一行命令

1
./acme.sh --issue --dns dns_ali -d example.com -d *.example.com

不过先别急着运行,我稍微解释下

先说上面这行命令中的几个参数,--issue就是要生成证书,--dns dns_ali就是使用dnsapi的方式完成认证且对应的厂商是阿里云,-d--domain的简写,就是指定对应的域名。注意这里指定了两个域名,且有一个是泛域名,这是因为acme支持生成SAN证书和通配符证书

除此之外,现在acme设置的默认CA是ZeroSSL,如果不想用这家,比如想换成Let’s Encrypt,那么需要在后面加一个选项--server letsencrypt。或者为了避免某次忘记加参数,可以运行下面这行命令把自己的默认CA改成Let’s Encrypt

1
./acme.sh --set-default-ca --server letsencrypt

还有一个参数,可能绝大多数不会用到,就是证书的加密算法。目前默认是ECDSA P-256,也就是使用ECC加密算法,如果想用RSA加密算法或者想修改加密程度,可以使用keylength参数,例如--keylength 4096代表使用RSA加密,密钥长度4096位,真的用到的话可以通过./acme.sh -h看对应的帮助文档。关于ECC和RSA可以看腾讯云的这个对比表格

现在可以根据自己需要运行命令生成证书了,当前目录应该会多出一个example.com_ecc的文件夹,文件夹内有一堆文件,一般只需要其中的两个文件,fullchain.cerexample.com.key。前者是包含中间证书的完整的公钥,后者是对应域名的私钥。私钥主要妥善保存和传输,不要泄露了。另外,文件名和格式可以随便改,比如后缀改成.pem之类的,注意别把内容改了就行。

到这一步,证书的签发就完成了,默认情况下acme会自动添加一个cron job,这会自动续期生成的证书。

原理简述

使用dnsapi这种方式签发证书,其原理就是通过调用相关厂商的API给对应的域名加一条TXT记录,然后再去通过DNS查询查这条记录的值是否匹配,来验证域名的归属是正确的。最后操作完会自动把这条记录删除,所以个人是无感的。实际上acme也支持dns manually的方式,就是不调用API了,手工完成前面的这些工作,不过这个就太麻烦了,一般不推荐。

Webroot

这种方式我极少用,使用场景一般是DNS API没法用,然后恰好有一个web服务在运行,并且这个网站是公网可访问的。

假设已经配置好了一个nginx服务,监听了80端口,其中静态文件的存放目录是/var/www/html,当前用户对这个目录具备写文件的权限。

然后依然是在~/.acme.sh目录下,直接运行命令

1
./acme.sh --issue -d example.com -w /var/www/html

注意这里没有--dns选项,改成了-w,至于其他的--server letsencrypt之类的选项则和上面一样,按需添加。

这种方式的原理是,acme会在静态文件夹内生成个文件,然后通过http访问对应的文件,如果文件内容一致那么说明域名归属没问题。同样最后会把文件清理掉。

Standalone

这种方式用的倒是不少,有时候在小众厂商搞了个年抛域名,就用这种方式申请证书。

同样需要在公网服务器操作,不过不需要部署nginx之类的服务,只需要安装socat这个命令行工具即可。使用的命令是

1
./acme.sh --issue -d example.com --standalone

默认会占用80端口,也可以通过--httpport参数来改成其他端口,比如改成88端口就在后面补充--httpport 88

这其实就是用socat代替了nginx等web服务,申请的证书用途是非web服务的时候,用这种方式会更方便。

总结

除了上面提到的我会用到的三种方式,官方还支持很多种签发证书的方式,甚至还能混合使用。

申请证书 + 自动续期,一行命令就可以搞定,这确实方便。但是对我而言,还有一些问题没有得到解决,比如我想知道证书续期之后通知我一下,我还想要在证书续期之后自动部署。这些acme都可以做到,不过就要稍微麻烦点了,下一篇文章再来讲。