更新
- 目前有更合适的证书提供商,同样基于acme.sh,本文以下节仅供参考;
- 更新或者重新安装最新的acme.sh后,证书提供商默认更改为zerossl,按照引导注册后即可使用;
- 注意请尽量手动控制dns验证,而非默认的自动,否则依然容易出现dns验证超时的问题(gfw猜想),参考命令:
acme.sh --issue --dns dns_ali --dnssleep 30 -d test3207.com -d *.test3207.com
- 其中
--dnssleep 30
即手动设置不验证dns,只休眠30秒,假装验证成功
- 更新后似乎解决了旧版定时任务随机失败的问题;
简介
现在https已经很普及了,未来除了兼容需要外,http基本都要转为https。需要关注的问题有这些:为什么证书是必要的?证书有哪些类型?如何优雅地管理证书?本篇主要结合自己的实践,讲一下后面两部分。
需要什么类型的证书
证书类型
证书是对域名的验证。
按验证主体分,证书主要分为DV(Domain Validation)、OV(Organazation Validation)、EV(Extend Validation)。
DV是仅对域名进行验证的类型。比如我告诉你,test3207.com这个域名是我的,你通过https访问该域名,就能获取我的网站内容。这一验证方式只能证明该域名下的内容是属于域名拥有者,并不能证明域名拥有者真实身份。因此,这一验证方式是可以自动化进行的。
OV则包含了对域名拥有者现实身份的验证,通常申请时,需要提供企业真实的相关信息。而EV同样也包含企业身份验证,不同的是根据不同企业的具体需要,会增加更多安全措施,特定机构发行的证书可以被特定的软件所识别。由于需要现实身份验证,这两者都无法做到自动化,需要专人处理。因此需要出一些服务费。
按域名类型分,证书主要分为单域名证书、多域名证书、通配符证书。
单域名证书就是一张证书只验证一个具体的域名:例如有一张 test3207.com 的证书,那么它只对 test3207.com 这一个域名生效,例如 www.test3207.com 这样的域名是无效的。多域名证书与之类似,一张证书内可以包含多个具体的域名。
通配符证书则可以匹配整个三级域名:例如有一张 *.test3207.com 的证书,那么 www.test3207.com 、 blogs.test3207.com 等任意三级域名都是可用的。(遗憾的是这张证书对 test3207.com 本身反而无效,需要按多域名证书的写法把它加进去)
目前任意主流浏览器,地址栏前方有个类似于锁的标示,点击后可以直接查看当前网站的证书信息,例如:
可以看到CA机构、起止时间、申请机构等关键信息,是一张EV型的通配符证书。
相比之下,DV型证书提供的信息就不包括申请机构,你可以直接查看本站证书对比。
选择证书
DV和OV(EV)的主要区别在于是否验证现实身份。有意思的是,域名服务商也会记录购买者的一些身份信息,例如注册邮箱、地址,虽然购买者也可以要求域名服务商隐藏这些信息,又或者有些域名服务商会直接显示服务商自己的信息,这也可以作为间接信源。因此,只有涉及直接利益相关、或者意义重大的域名,才有OV(EV)验证的必要。
域名类型首选通配符域名。除非确实只有开设确定的、有限个数服务的必要。多域名证书会对性能造成一定影响,单独为每个服务申请不同的证书,管理上又比较麻烦,前期管理维护的成本可能会稍微多一些,尤其是对于中小企业及个人开发者而言。(写到这里悄悄看了一眼,狗家软家都是单域名,牢厂月饼厂都是通配符,意外地阵营一致233)
简单来讲,DV通配符证书是适用范围最广的一种。
管理证书
CA交互
这里申请的是let’s encrypt的免费CA机构。你需要向CA证明你拥有该域名的所有权,简单来讲就是证明你可以控制该域名的解析。目前一共有两种方式:基于web服务,将某指定子域名指向某指定资源;基于dns,直接解析某子域名为某指定dns记录。我这里要申请的通配符域名只支持dns验证。国外有很多云服务提供商支持直接托管验证,遗憾的是,国内云服务商普遍不支持。所幸整个流程并不复杂:
首先要发送验证请求:本地生成一对sha-256密钥,请求包中包含公钥以及需要验证的域名,返回具体要求的验证方式;
然后在域名服务商处按要求修改对应的地址解析,一般是添加某TXT记录;
随后CA进行验证,到此域名的所有权已验证完毕,这对密钥可以保留30日。
之后就可以正式申请证书。每一张证书还需要单独的一对密钥进行验证,将通配符域名先经过这对密钥的私钥加密,再将整个信息使用前面域名验证的私钥加密,向CA发送以申请证书。CA通过公钥验证后,再用CA自己的签发私钥加密后回传。
LE官方推荐使用certbot进行证书管理,然而其自动化程度有限,dns验证部分,要完全自动化的话,需要自己根据相应的域名服务商提供的API编写对应的脚本。虽然已经有人写出了一些脚本,但是不都是基于shell的,用起来还是多多少少有些不便。这里更推荐使用acme.sh。
- 安装:
1 | curl https://get.acme.sh | sh |
- 签发:
1 | export Ali_Key="udontknow" |
这是基于阿里云的一张通配符证书,其他服务商可以参考这里对应修改。
在安装acme.sh时已经加入了cron服务,签发后会定期续期证书,不再需要手动跑命令。
这里可以直接修改~/.acme.sh/account.conf的相应密钥对,当然更推荐整个服务全部docker化,毕竟改cron和随便暴露全局变量对于洁癖来说还是很难忍受的XD。
配置证书
目前主流后端语言都可以直接以https方式启动,在程序内直接载入ssl证书。这样会带来一些运维上的问题,不利于统一维护管理。从运维方便的角度来讲,最好是将证书统一配置在负载均衡层,反代转发时统一使用证书。这里给出一个nginx下的参考样例:
1 | if ($host ~* "^(.*?)\.test3207\.com$") { |
证书签发完后,一般是保存在~/.acme.sh/文件夹内,acme.sh官方建议不直接使用该目录,以防后续目录结构更改,而使用
1 | acme.sh --installcert -d test3207.com \ |
这样的形式,手动将证书复制到指定文件夹内。
如果是直接在主机上运行的话,–reloadcmd参数可以直接填入”nginx -s reload”,签发或续期完成后,会直接运行该命令进行重启。
如果是通过docker的话,只将证书复制到Volumn内,reload在主机,容器内不填参数。主机定时重启nginx。
后话
最终效果是,只要不换服务器和域名,这套东西能用到LE不想干了为止。也正因为这样,整套流程因为用的次数太少有可能忘。写下此文以供参考。
另外,硬要讲的话,还需要考虑LE方访问API频率问题,以及吊销证书问题。实际上很难遇到这种情况。如有需要建议进一步参考LE官方文档。