使用命令行更新群晖的SSL证书

最近新学会了一招,使用Cloudflare的Origi 规则将443端口重定向到非标端口上,突破了家宽无法使用443端口的限制。部分没有公网访问需求的服务就解析到了局域网地址,限制只能在局域网或VPN下访问。万万没想到却在证书上遇到了问题。

正常情况下使用Cloudflare在开启代理的状态下会使用Cloudflare的边缘证书,采取不同的SSL/TLS加密模式,后端完全可以不用操心证书的问题。

基本情况及需求

  • 将解析地址设置成了私有地址后,无法开启Cloudflare的代理,这种状态下则需要使用后端自己的SSL证书。
  • 因为使用自己的域名,访问时会报证书不匹配,需要手动再点击继续访问。
  • 在VPS上已经使用acme.sh定时申请了通配符证书。

简单整理一下需求就是群晖需要定期从VPS服务器上取出SSL证书并将更新相关服务的证书

如何实现

第一步,同步证书

因为VPS的证书会在固定的目录,因此最简单的方式就是直接使用scp命令从固定的路径将证书文件取回到本地。为了避免输入密码,直接配置使用证书登录ssh。

第二步,更新证书

我们先进入控制面版,在 安全性 -> 证书 下把我们的通配符证书维护进去。在导入时记得填写描述信息,方便我们后续定位证书位置。

另外还需要在 安全性 -> 证书 -> 设置 -> 配置 中为相关服务选择正确的证书

通过网上搜索发现DSM将所有证书信息存放在了/usr/syno/etc/certificate/_archive目录下。在进入这个目录ls看下目录结构

root@KIMI-NAS:/usr/syno/etc/certificate/_archive# ll
total 52
drwx------ 9 root root 4096 Jan 25 14:25 .
drwxr-xr-x 8 root root 4096 Jul 28 21:58 ..
drwx------ 2 root root 4096 Dec 11 19:50 1opzpW
drwx------ 2 root root 4096 Jan 23 21:41 Bqb1Sn
-rw------- 1 root root    7 May 30  2020 DEFAULT
drwx------ 2 root root 4096 Jan  9  2023 FDutGe
drwx------ 2 root root 4096 Dec 19 09:04 FS7mk5
drwx------ 2 root root 4096 Jan 24 15:15 GMZqWq
-rw------- 1 root root 3982 Jan 25 14:25 INFO
drwx------ 2 root root 4096 May  1  2022 r6JawJ
-rwx------ 1 root root 2676 Jan 25 14:25 SERVICES
-rw-r--r-- 1 root root   41 Jan 24 15:15 .syno-ca-cert.srl
drwx------ 2 root root 4096 Dec 19 09:05 Thberd
root@KIMI-NAS:/usr/syno/etc/certificate/_archive#

看起来证书就在这些文件夹下,如何定位到我们新维护进去的证书呢?聪明的你一定发现了下面有个INFO证书,cat一下

root@KIMI-NAS:/usr/syno/etc/certificate/_archive# cat INFO
{
   "1opzpW" : {
      ...
   },
   "Bqb1Sn" : {
      ...
   },
   "FDutGe" : {
      ...
   },
   "FS7mk5" : {
      ...
   },
   "GMZqWq" : {
      "desc" : "kimi360.top",
      ...
   },
   "Thberd" : {
      "desc" : "Synology DDNS Certificate",
      ...
   },
   "r6JawJ" : {
      ...
   }
}
root@KIMI-NAS:/usr/syno/etc/certificate/_archive#

文件为json格式,decs就是你之前填入的描述信息,找到对应的描述信息就能确定刚才维护进去的证书在那个文件夹下,比如我这里就是GMZqWq这个文件夹,当然也可以简单的通过文件夹的时间去判断。

确定了证书的位置后接下来的工作就简单了。定时将文件夹中的文件替换,授权就可以了。

第三步,重启服务

更新完证书后最后一步就是重启相关服务让证书生效了。因为我这里只使用到了群晖的反向代理服务,因此只需要重启nginx即可

/usr/syno/bin/synosystemctl restart nginx

重启的时间会比较长,中途可能出现部分服务无法访问的情况,重启完成后在浏览器中就可以看到正确的证书了

脚本化

接下来,将我们的操作脚本化。在下载文件后使用diff命令与原证书文件进行比较,只有发生变化的情况下才会做证书的更新,避免每次下载后都重新启动相关服务的尴尬

# Synchronize and update certificate files from VPS
#!/bin/bash
declare -A CERT_FILE_LIST
# 服务器端的证书位置
REMOTE_PATH=...
# 本地证书ID
CERT_ID=
# 临时目录
TEMP_PATH=...
# 证书目录
CERT_PATH=/usr/syno/etc/certificate/_archive/${CERT_ID}/
# 证书对应关系
CERT_FILE_LIST["fullchain.pem"]="server.crt"
CERT_FILE_LIST["privkey.pem"]="server.key"
CERT_FILE_LIST["cert.pem"]="server.crt"

# 下载远端证书
mkdir -p ${TEMP_PATH}
for key in ${!CERT_FILE_LIST[@]};do
  scp root@vps:${REMOTE_PATH}/${CERT_FILE_LIST[${key}]} ${TEMP_PATH}${key}
done

# 比较证书目录与临时目录确定文件是否更新
if ! diff ${CERT_PATH} ${TEMP_PATH} > /dev/null;then
  # 证书更新,替换证书,授权后重启相关服务
  echo "Found a new certificate"
  mv ${TEMP_PATH}*.pem ${CERT_PATH}
  chown root:root ${CERT_PATH}*
  chmod 600 ${CERT_PATH}*
  /usr/syno/bin/synosystemctl restart nginx
else
  echo "The certificate is up-to-date"
fi

# 删除临时目录
rm -rf ${TEMP_PATH}

参考文献

updating_ssl_certificates_from_the_command_line

Synology: Import wildcard certificate from pfSense plus certificate renewal automation with Tux

本文链接 https://blog.kimi360.top/1ad1547eaf1c/

本文采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。