这是我第一次尝试通过 Certbot 更新 Let's Encrypt 证书。仔细阅读 Certbot 用户指南后,我创建了两个如下的后挂钩脚本:
root@pelargir:~# ls -l /etc/letsencrypt/renewal-hooks/post
total 8
-rwxr-xr-x 1 root root 697 Aug 29 16:35 10-setup-courier.sh
-rwxr-xr-x 1 root root 377 Aug 29 16:32 20-restart-services.sh
然后我在命令行上手动运行了续订过程(即不通过 cron)。这成功续订了证书,但未能执行上述后挂钩脚本。以下是相关输出:
[...]
Running post-hook command: /etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh
Hook command "/etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh" returned error code 127
Error output from 10-setup-courier.sh:
/bin/sh: /etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh: not found
Running post-hook command: /etc/letsencrypt/renewal-hooks/post/20-restart-services.sh
Hook command "/etc/letsencrypt/renewal-hooks/post/20-restart-services.sh" returned error code 127
Error output from 20-restart-services.sh:
/bin/sh: /etc/letsencrypt/renewal-hooks/post/20-restart-services.sh: not found
[...]
我不知道为什么会发生这种情况。我仔细检查了一下:
- 脚本文件存在
- 脚本文件是可执行的
- 我可以手动运行脚本(使用环境变量
RENEWED_DOMAINS
并RENEWED_LINEAGE
设置和导出),它们会按预期完成工作
我可能应该提到的另一件事是,我在 Docker 映像中运行 Certbot,因为我正在使用通配符证书。我的 DNS 提供商是 Cloudflare。这是我用来启动续订过程的命令行:
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
certbot/dns-cloudflare
renew
Docker 镜像运行 Certbot 版本 0.25.0。系统是 Debian 9(stretch),最近从 Debian 8(jessie)升级而来。
有什么线索可以知道问题是什么吗?
编辑:根据要求,以下是两个文件的内容,稍加编辑以将我的域名替换为“example.com”:
root@pelargir:~# cat /etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh
#!/bin/bash
# Exit immediately if a command exits with non-zero status
set -e
case $RENEWED_DOMAINS in
# Courier runs only under a example.com subdomain
example.com)
# We don't care about file permissions because we know that the
# filesystem folder where we generate the file is not generally
# accessible
cat "$RENEWED_LINEAGE/fullchain.pem" "$RENEWED_LINEAGE/privkey.pem" >"$RENEWED_LINEAGE/courier.cert-and-key.unsecure"
;;
esac
root@pelargir:~# cat /etc/letsencrypt/renewal-hooks/post/20-restart-services.sh
#!/bin/bash
# Exit immediately if a command exits with non-zero status
set -e
case $RENEWED_DOMAINS in
# Courier and Exim run only under a example.com subdomain
*example.com*)
systemctl restart courier-imap.service
systemctl restart exim4.service
systemctl restart apache2.service
;;
# Apache has vhosts for all domains. Unfortunately the daemon is
# restarted several times if several certificates are renewed.
*)
systemctl restart apache2.service
;;
esac
答案1
您的 shell 脚本使用了 shebang #!/bin/bash
,这意味着它们将使用该程序执行,但它们运行的 Docker 容器不包含 bash。这就是为什么在调用这些明显存在的脚本时/bin/sh
会报告令人困惑的not found
错误。不是找不到脚本,而是您要求用来运行它们的 bash 解释器。
/bin/sh
您可以通过更改脚本解释器并从脚本中删除任何 bash-isms(可能快速且简单)或者在容器中安装 bash(可能很混乱)来解决问题。