RESEARCH / PRACTICE / NOTES

群晖配置 ZeroSSL 泛域名证书:签发、部署与续期

在 DSM 7 上使用 acme.sh、ZeroSSL 和 Cloudflare DNS 验证签发泛域名证书,再通过 DSM 部署钩子更新证书,并交给任务计划程序续期。

#家庭网络#数字安全
关键词TLS证书
存储设备的金属细节与钥匙透明影像交叠
本文目录 · 5 个章节
  1. 先把账号和权限准备好
  2. 安装 acme.sh
  3. 注册 ZeroSSL 并签发证书
  4. 把证书交给 DSM
  5. 让续期真正跑起来

家里有一台群晖,服务多起来以后,浏览器里可能会出现 nas.example.com、photos.example.com 这样的地址。逐个给子域名处理证书很琐碎;如果这些名字属于同一个域名,可以签发一张同时包含 example.com 和 *.example.com 的证书,再分配给 DSM 中需要它的服务。

这里用 DSM 7、ZeroSSL、Cloudflare DNS 和 acme.sh 走一遍。域名需要由 Cloudflare 管理 DNS,命令里的 example.com 则要换成你自己的域名。证书签发使用 DNS-01 验证,群晖不必为了验证证书开放 80 或 443 端口。证书解决的是 HTTPS 身份与加密问题,服务能否从外网访问仍取决于你的网络配置。

先把账号和权限准备好

在 ZeroSSL 注册账号,进入控制台的 Developer 页面生成 ACME 用的 EAB KID 和 HMAC Key。这两个值用于注册 ACME 账号,不是 ZeroSSL 的登录密码,也不是一般 API Access Key。

Cloudflare 这边创建一个 API Token,只授权需要签证书的域名。权限给 Zone / DNS / Edit 和 Zone / Zone / Read,资源范围选对应的 Zone;不要使用整个账户的 Global API Key。再到该域名的概览页记下 Zone ID。ZeroSSL 的 EAB 凭据和 Cloudflare Token 都不要放进公开脚本或截图里。

群晖控制面板的「终端机和 SNMP」中启用 SSH。先用有管理员权限的账号登录,再执行 sudo -i。后面的命令都在群晖本机、以 root 身份运行;配置结束后,可以关闭 SSH,或只允许它从可信内网访问。

安装 acme.sh

从 acme.sh 项目下载程序,在群晖上安装。这里不让安装程序额外创建定时任务,续期交给 DSM 的任务计划程序。

sudo -i
umask 077
cd /tmp
curl -fL https://github.com/acmesh-official/acme.sh/archive/refs/heads/master.tar.gz -o acme-sh.tar.gz
tar -xzf acme-sh.tar.gz
cd acme.sh-master
./acme.sh --install --nocron --home /usr/local/share/.acme.sh --accountemail '[email protected]'
/usr/local/share/.acme.sh/acme.sh --version

把邮箱改成自己的。若 curl 或解压失败,先处理下载问题,不要跳过错误继续执行。acme.sh 的工作目录里会存放证书私钥和续期所需配置,应只允许管理员读取,也不要把这个目录放到共享文件夹中。

注册 ZeroSSL 并签发证书

先输入 EAB 凭据。下面的输入不会写进 shell 历史记录,-s 让输入时不回显;粘贴后按回车即可。

read -r -s -p 'EAB KID: ' EAB_KID; printf '\n'
read -r -s -p 'EAB HMAC Key: ' EAB_HMAC_KEY; printf '\n'
/usr/local/share/.acme.sh/acme.sh --register-account \
  --home /usr/local/share/.acme.sh \
  --server zerossl \
  --eab-kid "$EAB_KID" \
  --eab-hmac-key "$EAB_HMAC_KEY"
unset EAB_KID EAB_HMAC_KEY

接着输入 Cloudflare Token 和 Zone ID,再签发证书:

read -r -s -p 'Cloudflare API Token: ' CF_Token; printf '\n'
read -r -p 'Cloudflare Zone ID: ' CF_Zone_ID
export CF_Token CF_Zone_ID

/usr/local/share/.acme.sh/acme.sh --issue \
  --home /usr/local/share/.acme.sh \
  --server zerossl \
  --dns dns_cf \
  -d example.com \
  -d '*.example.com' \
  --keylength ec-256

unset CF_Token CF_Zone_ID

dns_cf 会临时添加并清理 DNS 验证记录。这里同时写了根域和通配符,是因为 *.example.com 本身不覆盖 example.com;它也不覆盖 a.b.example.com 这样的更深一级子域。ec-256 签发的是 ECC 证书,后面部署时同样要指定 --ecc。

Cloudflare Token 会被 acme.sh 保存到受保护的证书配置中,供以后续期使用;unset 只是清除当前终端里的变量,并不会删除续期凭据。若 Token 过期或被撤销,下一次 DNS 验证就会失败。

把证书交给 DSM

签发成功只代表 acme.sh 拿到了证书,群晖还没有开始使用它。下面通过本机的 synology_dsm 部署钩子导入证书。这个钩子会临时创建管理员账号完成导入,正常结束后删除,因此不需要在续期配置里保存你平时使用的 DSM 管理员密码。

第一次运行前,先在 DSM 用户列表确认没有名为 sc-acmesh-tmp 的现有账号;部署钩子使用这个固定名称,若它已被占用,不要直接执行。以下示例会在 DSM 证书列表里建立名为「ZeroSSL 泛域名」的证书,之后续期会更新这同一项。

export SYNO_USE_TEMP_ADMIN=1
export SYNO_CERTIFICATE='ZeroSSL 泛域名'
export SYNO_CREATE=1

/usr/local/share/.acme.sh/acme.sh --deploy \
  --home /usr/local/share/.acme.sh \
  -d example.com \
  --ecc \
  --deploy-hook synology_dsm

此处默认通过群晖本机的 localhost:5000 管理接口导入。如果 DSM 使用了不同的本地 HTTP 管理端口,需要在部署前设置相应的 SYNO_PORT。不要把管理接口暴露到公网来迁就这一步。

导入后,打开「控制面板 → 安全性 → 证书」,确认新证书存在,并在证书设置中把它分配给 DSM、反向代理或相应套件。导入成功不等于所有服务已经改用新证书。如果部署过程中意外中断,也检查一下 DSM 用户列表,确认临时账号已被清理。

让续期真正跑起来

ZeroSSL ACME 证书有效期为 90 天,不应等浏览器提示过期才处理。在「控制面板 → 任务计划程序」新增「计划的任务 → 用户自定义脚本」,用户选 root,设为每天运行一次,脚本填写:

/usr/local/share/.acme.sh/acme.sh --cron --home /usr/local/share/.acme.sh

每天检查不等于每天重签。acme.sh 会判断是否到了续期时间;续期成功后,已经登记的 DSM 部署钩子会再次运行。保存任务后手动运行一次,确认任务执行正常。此时若证书还没到续期时间,看到它跳过签发是正常现象。建议开启 DSM 的任务失败通知,并定期看一次证书有效期,别把“计划任务存在”当成“续期已经验证”。

最后可以在 SSH 中检查证书本身:

openssl x509 \
  -in /usr/local/share/.acme.sh/example.com_ecc/fullchain.cer \
  -noout -dates -ext subjectAltName

输出中应能看到根域、通配符和有效期。再用浏览器访问一个实际分配了该证书的服务,查看浏览器收到的证书是否相同。两处都对得上,这套配置才算完成。

若签发失败,先查 Cloudflare Token 的 Zone 范围、权限及 _acme-challenge.example.com 的 TXT 记录是否能被解析;若证书已经签发却没有出现在 DSM,查部署钩子的返回信息和本机管理端口;若 DSM 里证书正确而浏览器仍提示旧证书,重点看该服务的证书分配,而不是反复重新签发。证书问题拆开查,比一开始就强制重签更容易找到原因。

交流与讨论

评论加载中…

随便读一篇 →

站内搜索

输入关键词开始搜索。

搜索内容不会上传 Esc 关闭

订阅明月入怀

将下面的网址添加到你的 RSS 阅读器。