为什么 Certbot 无法运行 post hook 脚本?

her*_*ube 0 lets-encrypt certbot

这是我第一次尝试通过 Certbot 更新 Let's Encrypt 证书。仔细阅读 Certbot 用户指南后,我创建了两个如下的 post hook 脚本:

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
Run Code Online (Sandbox Code Playgroud)

然后我在命令行上手动运行更新过程(即不通过 cron)。更新证书成功,但未能执行上述 post hook 脚本。这是相关的输出:

[...]
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
[...]
Run Code Online (Sandbox Code Playgroud)

我不知道为什么会发生这种情况。我仔细检查了一下:

  • 脚本文件存在
  • 脚本文件是可执行的
  • 我可以手动运行脚本(使用环境变量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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

Mic*_*ton 5

您的 shell 脚本使用 shebang #!/bin/bash,这意味着它们将使用该程序执行,但它们运行的​​ Docker 容器不包含 bash。这就是为什么在调用这些明显存在的脚本时/bin/sh会报告令人困惑的错误。not found并不是找不到脚本,而是您要求运行它们的 bash 解释器。

/bin/sh您可以通过更改脚本解释器并从脚本中删除任何 bash-ism(可能快速且简单)或通过在容器中安装 bash(可能很混乱)来解决问题。