Certbot がポストフック スクリプトの実行に失敗するのはなぜですか?

Certbot がポストフック スクリプトの実行に失敗するのはなぜですか?

これは、Certbot 経由で Let's Encrypt 証明書を更新する初めての試みです。Certbot ユーザー ガイドを注意深く読んだ後、次のような 2 つのポスト フック スクリプトを作成しました。

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エクスポートします)。スクリプトは期待どおりに機能します。

もう 1 つ言及しておくべきことは、ワイルドカード証明書を使用しているため、Certbot を Docker イメージ内で実行していることです。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」に置き換えるために少し編集した 2 つのファイルの内容を以下に示します。

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

シェル スクリプトは shebang を使用します#!/bin/bash。つまり、そのプログラムで実行されることになりますが、スクリプトが実行される Docker コンテナーには bash が含まれていません。明らかに存在するこれらのスクリプトを呼び出すときに、/bin/sh混乱を招くnot foundエラーが報告されるのはそのためです。見つからないのはスクリプトではなく、スクリプトを実行するように要求した bash インタープリターです。

この問題は、スクリプト インタープリターを変更して/bin/shスクリプトから bash 関連の要素を削除する (おそらく迅速かつ簡単) か、コンテナーに bash をインストールする (おそらく面倒) ことで解決できます。

関連情報