有几个在腾讯云申请的域名,过去这几个域名一直使用的是腾讯云的免费证书。之前这些证书使用期限是1年,在2024年4月25号之后,证书有效期改成了3个月,后面要想保住ssl,就得每3个月换一次证书,这是逼人购买付费证书的节奏。

幸好世界上还有acme这样的好东西,可以自动化的申请、部署证书。

我的群晖和外网的服务器上都有绑定域名的服务,打算将acme部署在群晖上,原因有两点,

  1. 群晖自身的域名需要更新,acme部署在群晖上方便给群晖更新,同时也能通过ssh的方式给外网服务器更新,如果部署在外网,那么外网服务器可不方便给群晖更新(需要内网穿透)。
  2. 群晖更加稳定,云服务器后面可能随时更换上新。

一、安装

acme可以通过脚本或是docker的方式安装,这里我使用脚本安装的方式,原因是通过脚本安装的话,acme可以直接调用群晖本地的工具生成临时用户进行证书安装。如果是docker安装的方式,需要提供群晖系统管理员的账号密码信息,存在信息泄露的风险。

通过ssh登录群晖,执行以下命令安装acme。

1
2
3
4
5
6
7
8
# 切换到root账户
sudo su

# 进入root home目录
cd ~

# 安装
curl https://get.acme.sh | sh -s email=my@example.com --force

二、使用

acme申请域名证书主要分为几个步骤,

  1. 获取域名服务商API Token,用于域名申请时的所有权验证。
  2. 申请证书。
  3. 部署安装证书。
  4. 配置证书自动更新。

2.1 获取域名服务商API Token

验证所有权一般有两种方式。

  1. 在绑定域名的http服务器下放一个特殊文件,证书服务商通过http服务检测到这个文件后,确认域名所有权。
  2. 给域名添加一条txt解析记录,证书服务商检测到这条解析记录后,确认所有权。

这里我更推荐第二种方式,相较第一种方式更为灵活。第一种方式必须要要有一个公网环境下的http服务器,但对于我这种需要部署在家里群晖上的情况来说,暴露一个公网环境的http服务还是比较麻烦的。

acme支持自动给域名添加txt解析记录,前提是需要我们提供域名服务商的API Token信息,以便acme能够通过域名服务商的API进行修改。

我的域名由cloudflare进行管理,因此这里以cloudflare进行演示。

在cloudflare域名页面的右下角可以看到API相关的信息。这里我们记录下Account ID信息,之后点击Get your API token

Get your API token页面,基于 DNS模板 创建一个新的token。

按照上图示例创建好token后记录下来,后面会用到。

2.2 申请证书

在安装部分,将acme安装到了root账户的home目录下,即/root/.acme.sh中。

接下来执行命令用于证书申请。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 设置CF Account信息
export CF_Account_ID="your account" 

# 设置CF Token信息
export CF_Token="your token"

# 进入/root/.acem.sh目录
cd /root/.acme.sh

# 申请证书,--server letsencrypt 指定申请 letsencrypt 证书
# -d example.com 指定要申请证书的域名是 example.com
# -d *.example.com 说明申请的证书是泛域名证书
./acme.sh --issue --server letsencrypt --dns dns_cf -d example.com -d *.example.com

若无意外,证书将会申请成功,并存放在.acme目录下。

2.3 部署证书

接下来,我们需要分别将证书部署到群晖和远端服务器上。

2.3.1 部署到群晖

前面提到,我们采用脚本的形式安装了acme,为的就是在不需要群晖账户信息的情况下部署证书,执行以下命令部署。

1
2
3
4
5
6
# 设置使用临时管理员账户
export SYNO_USE_TEMP_ADMIN=1

# 在/root/.acme.sh目录下执行命令部署证书
# example.com是前面申请证书的域名
./acme.sh --deploy --deploy-hook synology_dsm -d example.com

若无意外,群晖的证书将会部署成功,相较于使用docker安装acme的方式来说,完全不需要我们的账户信息,非常简单。

2.3.2 部署证书到远端服务器

部署到服务器需要使用ssh的部署方式,这要求在群晖上可以通过ssh连接到公网的服务器上。

公网的服务器使用ssh密钥的方式登录,不建议使用密码,不安全。假设已经配置好使用密钥的方式连接远端的服务器,那么接下来把私钥放在群晖/root/.ssh目录下,命名为id_rsa,同时创建config文件,内容如下。

1
2
3
4
Host remote_server
    HostName <ip>
    User <user_name>
    IdentityFile /root/.ssh/id_rsa

接下来继续配置acme。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 设置ssh登录用户,即config中的 User 信息
export DEPLOY_SSH_USER=<user_name>

# 设置ssh登录的服务器,这里是config中的 remote_server 这个名字
export DEPLOY_SSH_SERVER=remote_server

# 设置申请到的证书key文件要拷贝到远端服务器的路径,假设是 /etc/nginx/ssl/example.com.key
export DEPLOY_SSH_KEYFILE='/etc/nginx/ssl/example.com.key'

# 设置申请到的证书链文件要拷贝到远端服务器的路径,假设是 /etc/nginx/ssl/fullchain.csr
export DEPLOY_SSH_FULLCHAIN='/etc/nginx/ssl/fullchain.csr'

# 设置拷贝证书完毕后,要在远端服务器执行的命令,这里重新加载nginx服务器
export DEPLOY_SSH_REMOTE_CMD='sudo nginx -s reload'

# 执行部署命令
./acme.sh --deploy -d example.com --deploy-hook ssh

2.3.3 同时部署到群晖和服务器

以上我们分别配置了使用了acme将证书部署在群晖和远端服务器上,由于acme只会记录我们最后执行的部署命令,因此我们需要一次性将证书部署到群晖和远端服务器上,这样acme在后续自动更新时,便能自动的将证书同时部署到群晖和远端服务器上。

使用下面的命令一次性将证书部署到群晖和远端服务器上。

1
./acme.sh --deploy -d example.com --deploy-hook ssh --deploy-hook synology_dsm

2.4 配置证书自动更新

由于群晖默认没有安装crontab,因此这里使用群晖的任务计划功能自动更新。

创建计划任务时需要指定使用root用户执行命令。计划部分,由于acme仅在证书到期前的一个月才会重新申请证书,稳妥起见,这里我设置每周检查一次。

最后的任务设置部分,需要设置要执行的更新命令。这里配置如下。

1
2
# 其中的--home为acme的安装目录,用于获取证书相关的信息
/root/.acme.sh/acme.sh --cron --home /root/.acme.sh

如果有配置邮件通知功能的话,也可以配置下要通知的邮箱地址。

三、最后

至此,使用acme自动更新部署证书的工作就完成了,接下来就享受acme带来的便捷吧,再也不用手动更新证书了 😁。

参考资料

  1. dnsapi · acmesh-official/acme.sh Wiki
  2. deployhooks · acmesh-official/acme.sh Wiki
  3. 自动化部署证书 acme.sh 详细实践使用教程 - 思有云 - IOIOX
  4. 群晖DSM7.x通过acme.sh全自动更新并部署SSL证书 - Zakikun