acme.sh不能自动更新证书的问题

本文描述了一种使用acme.sh颁发的证书始终不能正常自动更新的问题,并记录了解决过程。

在服务器上使用了acme.sh来颁发ssl证书,按照官方指导在用户user1根目录下安装了acme.sh,并在root用户下执行如下命令(如不在root下执行,会报提醒,建议到root下执行),成功颁发了证书:

/home/user1/.acme.sh/acme.sh --set-default-ca --server letsencrypt --issue -d test_domain.com --standalone --keylength ec-256 --force

然后在root下执行了将证书安装到指定目录下的操作:

/home/user1/.acme.sh/acme.sh --install-cert -d test_domain.com --ecc \
--fullchain-file /etc/v2ray/v2ray.crt \
--key-file /etc/v2ray/v2ray.key \
--reloadcmd "systemctl reload nginx ; systemctl restart v2ray"

一切正常的话,按照官方所描述的,crontab中会每日自动检查证书是否需要renew,然后根据情况在快要到期时(acme.sh默认证书有效期为90天,到期前30天会自动更新。注意有效期最多只有90天,不能延长,参见此处)更新。

但是在实际操作中,始终不能如预期正常更新证书。user1下检查定时任务

sudo crontab -l

查看结果:

48 0 * * * "/home/user1/.acme.sh"/acme.sh --cron --home "/home/user1/.acme.sh" > /dev/null

由于一直没找到原因,故每次到期后都需要手动更新证书:

sudo ~/.acme.sh/acme.sh --renew -d test_domain.com --force --ecc --reloadcmd "systemctl reload nginx ; systemctl restart v2ray"

上述命令执行在用户user1下。最后的参数是在执行后重启nginxv2ray

手动更新正常(这很奇怪,可能是因为在rootuser1下都生成了证书,保留了两个目录下的参数与证书,并在根目录下生成证书时输入了错误的域名?检查发现root下也安装了acme.sh,将其卸载,并删除了.acme.sh/目录。)。

一直对acme.sh定时更新的工作流程,特别是为什么在crontab的定时任务里不需要传参的原因不是很理解,于是花了点时间检索,发现了相关解答。即在执行--install-cert后参数会保存,自动更新时调用之,故不需要在crontab中传参。

然后尝试直接debug执行更新操作:

"/home/user1/.acme.sh"/acme.sh --cron --home "/home/user1/.acme.sh" --debug

发现执行日志有如下内容:

[Thu Oct 12 10:33:01 UTC 2023] ===Starting cron===
[Thu Oct 12 10:33:01 UTC 2023] Using config home:/home/user1/.acme.sh
[Thu Oct 12 10:33:01 UTC 2023] ACME_DIRECTORY='https://acme.zerossl.com/v2/DV90'
[Thu Oct 12 10:33:01 UTC 2023] _stopRenewOnError
[Thu Oct 12 10:33:01 UTC 2023] _set_level='2'
[Thu Oct 12 10:33:01 UTC 2023] di='/home/user1/.acme.sh/*.*/'
[Thu Oct 12 10:33:01 UTC 2023] Not a directory, skip: /home/user1/.acme.sh/*.*/
[Thu Oct 12 10:33:01 UTC 2023] _error_level='3'
[Thu Oct 12 10:33:01 UTC 2023] _set_level='2'
[Thu Oct 12 10:33:01 UTC 2023] ===End cron===

从上述内容可见问题出现在参数配置文件目录出错,导致找不到.acme.sh/*.*/文件。这才意识到安装acme.sh脚本的目录是在user1根目录下,但是在申请证书是在root根目录下操作的。执行了:

sudo su -

造成目录切换到了root根目录下,运行--issue域名的操作生成的文件直接保存在了root根目录下,即证书、配置的目录与脚本的目录不匹配。程序自动更新时在脚本目录/home/user1/.acme.sh下寻找不到所需的证书与参数,因而出错、忽略了。加上日志直接输到了/dev/null,故一直没找到原因。

修改--homedebug

"/home/user1/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" --debug

发现结果显示包含如下内容:

[Thu Oct 12 10:47:17 UTC 2023] di='/root/.acme.sh/test_domain_ecc/'
[Thu Oct 12 10:47:17 UTC 2023] d='test_domain.com_ecc'
[Thu Oct 12 10:47:17 UTC 2023] Using config home:/root/.acme.sh
[Thu Oct 12 10:47:17 UTC 2023] ACME_DIRECTORY='https://acme.zerossl.com/v2/DV90'
[Thu Oct 12 10:47:17 UTC 2023] DOMAIN_PATH='/root/.acme.sh/test_domain.com_ecc'
[Thu Oct 12 10:47:17 UTC 2023] Renew: 'test_domain.com'
[Thu Oct 12 10:47:17 UTC 2023] Le_API='https://acme-v02.api.letsencrypt.org/directory'
[Thu Oct 12 10:47:17 UTC 2023] Using config home:/root/.acme.sh
[Thu Oct 12 10:47:17 UTC 2023] ACME_DIRECTORY='https://acme-v02.api.letsencrypt.org/directory'
[Thu Oct 12 10:47:17 UTC 2023] Skip, Next renewal time is: Mon Dec 11 09:52:50 UTC 2023

显然,这次脚本成功检查了证书的有效期,并跳过了不需要更新的证书。可判断这回脚本能够正确运行了。

root下修改crontab中的任务:

crontab -e

--home参数后的目录修改一下:

48 0 * * * "/home/user1/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

即可正常自动更新了。