随着免费 SSL 证书签发政策改变,证书有效期由之前的 1 年变为 3 个月,这是逼迫大家都购买付费证书啊。之前一年换一次,也还可以接受,结果现在一年要换好几次,又得申请又得部署,一不小心忘了还用不了,这就让人很不舒服了。所以便有了本文,让整个申请+部署流程自动化。
整体步骤如下:
使用 acme.sh 签发 SSL 证书
用脚本为域名配置证书
更新证书后自动部署
安装很简单,一条命令:
curl https://get.acme.sh | sh -s email=my@example.com
普通用户和 root 用户都可以安装使用。
安装过程进行了以下几步:
把 acme.sh 安装到你的 home 目录下 ~/.acme.sh/
,并创建 一个 shell 的 alias,例如 .bashrc
,方便你的使用:alias acme.sh=~/.acme.sh/acme.sh
自动为你创建 cronjob, 每天 0:00 点自动检测所有的证书,如果快过期了,需要更新,则会自动更新证书。
更高级的安装选项请参考:https://github.com/acmesh-official/acme.sh/wiki/How-to-install
acme.sh 实现了 acme 协议支持的所有验证协议。一般有两种方式验证: HTTP 和 DNS 验证。因为我们是为 CDN 生成证书,使用 DNS 自动验证(DNS API)的方式比较合适。
acme.sh 目前支持超过一百家的 DNS API。
以 DNSPod.cn 为例,你需要先登录到 DNSPod.cn,拿到你的 DNSPod API Key 和 ID 并设置:
export DP_Id="1234"
export DP_Key="sADDsdasdgdsf"
现在我们可以签发证书了:
acme.sh --issue --dns dns_dp -d example.com -k 2048
DP_Id
和 DP_Key
将保存在 ~/.acme.sh/account.conf
中,并在需要时自动获取,无需手动再设置。
-k 2048
用于指定使用 RSA 算法,不加这个参数默认使用 ECC 算法,目录也会带有 _ecc
后缀。
更详细的 DNS API 用法: https://github.com/acmesh-official/acme.sh/wiki/dnsapi
证书生成好以后,我们需要把证书复制给对应的 Apache、Nginx 或其他服务器去使用。
必须使用 --install-cert
命令来把证书复制到目标文件,请勿直接使用 ~/.acme.sh/
目录下的证书文件,这里面的文件都是内部使用,而且目录结构将来可能会变化。
首先创建一个目录用来存放证书:
mkdir -p ~/ssl/example.com
以 Nginx 为例,复制证书:
acme.sh --install-cert -d example.com \
--key-file ~/ssl/example.com/example.com.key \
--fullchain-file ~/ssl/example.com/example.com.cer
我们将生成的证书上传到阿里云 CDN 中,在此之前需要去阿里云控制台新增一个用户并添加 CDN 管理权限,然后获取到 accessKeyId 和 accessKeySecert:
~/ssl/upload.php
<?php
// composer require alibabacloud/cdn-20180510 "^4.2"
require __DIR__.'/vendor/autoload.php';
use AlibabaCloud\SDK\Cdn\V20180510\Cdn;
use AlibabaCloud\SDK\Cdn\V20180510\Models\SetCdnDomainSSLCertificateRequest;
use Darabonba\OpenApi\Models\Config;
$config = new Config([
'accessKeyId' => 'YOUR_ACCESS_KEY_ID',
'accessKeySecret' => 'YOUR_ACCESS_KEY_SECRET',
'endpoint' => 'cdn.aliyuncs.com',
]);
$client = new Cdn($config);
$certPath = '~/ssl/example.com/example.com.cer';
$keyPath = '~/ssl/example.com/example.com.key';
try {
$request = new SetCdnDomainSSLCertificateRequest([
'domainName' => 'example.com',
'SSLPub' => file_get_contents($certPath),
'SSLPri' => file_get_contents($keyPath),
'SSLProtocol' => 'on',
]);
$client->setCdnDomainSSLCertificate($request);
echo '上传成功';
} catch (\Exception $e) {
echo '上传失败: '.$e->getMessage();
}
加上可执行权限:
chmod +x ~/ssl/upload.php
重新生成证书,并在生成后上传证书:
acme.sh --renew -d example.com --renew-hook 'php ~/ssl/upload.php'
这样就 OK 了。