使用 acme.sh 自动续签 CDN 的 SSL 证书

老牛浏览 77评论 0发表于

一、问题说明

随着免费 SSL 证书签发政策改变,证书有效期由之前的 1 年变为 3 个月,这是逼迫大家都购买付费证书啊。之前一年换一次,也还可以接受,结果现在一年要换好几次,又得申请又得部署,一不小心忘了还用不了,这就让人很不舒服了。所以便有了本文,让整个申请+部署流程自动化。

二、解决方案

整体步骤如下:

  1. 使用 acme.sh 签发 SSL 证书

  2. 用脚本为域名配置证书

  3. 更新证书后自动部署

2.1 安装 acme.sh

安装很简单,一条命令:

bash
curl https://get.acme.sh | sh -s email=my@example.com

普通用户和 root 用户都可以安装使用。

安装过程进行了以下几步:

  1. 把 acme.sh 安装到你的 home 目录下 ~/.acme.sh/ ,并创建 一个 shell 的 alias,例如 .bashrc,方便你的使用:alias acme.sh=~/.acme.sh/acme.sh

  2. 自动为你创建 cronjob, 每天 0:00 点自动检测所有的证书,如果快过期了,需要更新,则会自动更新证书。

更高级的安装选项请参考:https://github.com/acmesh-official/acme.sh/wiki/How-to-install

2.2 生成证书

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_IdDP_Key 将保存在 ~/.acme.sh/account.conf 中,并在需要时自动获取,无需手动再设置。

-k 2048 用于指定使用 RSA 算法,不加这个参数默认使用 ECC 算法,目录也会带有 _ecc 后缀。

更详细的 DNS API 用法: https://github.com/acmesh-official/acme.sh/wiki/dnsapi

2.3 复制证书

证书生成好以后,我们需要把证书复制给对应的 Apache、Nginx 或其他服务器去使用。

必须使用 --install-cert 命令来把证书复制到目标文件,请勿直接使用 ~/.acme.sh/ 目录下的证书文件,这里面的文件都是内部使用,而且目录结构将来可能会变化。

首先创建一个目录用来存放证书:

bash
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

2.4 编写上传脚本

我们将生成的证书上传到阿里云 CDN 中,在此之前需要去阿里云控制台新增一个用户并添加 CDN 管理权限,然后获取到 accessKeyId 和 accessKeySecert:

~/ssl/upload.php

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();
}

加上可执行权限:

bash
chmod +x ~/ssl/upload.php

2.5 自动续期并上传证书

重新生成证书,并在生成后上传证书:

bash
acme.sh --renew -d example.com --renew-hook 'php ~/ssl/upload.php'

这样就 OK 了。

点赞
收藏
暂无评论,快来发表评论吧~
私信
老牛@ilaoniu
老牛,俗称哞哞。单纯的九零后理工小青年。喜欢折腾,爱玩,爱音乐,爱游戏,爱电影,爱旅游...
最后活跃于