为什么 Certbot 无法运行后挂钩脚本?

为什么 Certbot 无法运行后挂钩脚本?

这是我第一次尝试通过 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_DOMAINSRENEWED_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(可能很混乱)来解决问题。

相关内容