Let’s EncryptのSSL証明書をお使いの方も多いと思いますが、90日ごとに証明書が切れてしまいます。Let’s Encrypt事務局が証明書の期限をアラートしてくれますが、3ヶ月に一度といえど、SSHでログインしてコマンドを叩くのは忘れてしまいがちですよね。
このため、cronを使って自動更新を試みました。
# crontab -e
30 * * * * certbot renew --post-hook "systemctl restart nginx"
手動で動かしている certbot renew --post-hook "systemctl restart nginx"
を定期実行させてみます。このcrontabの内容は以下です。
- certbot renewコマンドでSSL証明書を更新
- 発行したSSL証明書を適用させるためにnginxを再起動
サンプルでは30分ごとになっていますが、90日以内に更新できればいいので、あくまで検証用です。
Mar 19 03:30:01 ip-172-31-24-233 CROND[7697]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Mar 19 03:30:01 ip-172-31-24-233 CROND[7698]: (root) CMD (certbot renew --post-hook "systemctl restart nginx")
Mar 19 03:30:02 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (Saving debug log to /var/log/letsencrypt/letsencrypt.log)
Mar 19 03:30:02 ip-172-31-24-233 CROND[7696]: (root) CMDOUT ()
Mar 19 03:30:02 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -)
Mar 19 03:30:02 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (Processing /etc/letsencrypt/renewal/example.com.conf)
Mar 19 03:30:02 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -)
Mar 19 03:30:02 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (Cert is due for renewal, auto-renewing...)
Mar 19 03:30:02 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (Non-interactive renewal: random delay of 384.201978393 seconds)
Mar 19 03:36:26 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (Could not choose appropriate plugin: The nginx plugin is not working; there may be problems with your existing configuration.)
Mar 19 03:36:26 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (The error was: NoInstallationError("Could not find a usable 'nginx' binary. Ensure nginx exists, the binary is executable, and your PATH is set correctly.",))
Mar 19 03:36:26 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (Failed to renew certificate example.com with error: The nginx plugin is not working; there may be problems with your existing configuration.)
Mar 19 03:36:26 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (The error was: NoInstallationError("Could not find a usable 'nginx' binary. Ensure nginx exists, the binary is executable, and your PATH is set correctly.",))
Mar 19 03:36:26 ip-172-31-24-233 CROND[7696]: (root) CMDOUT ()
Mar 19 03:36:26 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -)
Mar 19 03:36:26 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (All renewals failed. The following certificates could not be renewed:)
Mar 19 03:36:26 ip-172-31-24-233 CROND[7696]: (root) CMDOUT ( /etc/letsencrypt/live/example.com/fullchain.pem (failure))
Mar 19 03:36:26 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -)
Mar 19 03:36:26 ip-172-31-24-233 CROND[7696]: (root) CMDOUT (1 renew failure(s), 0 parse failure(s))
エラーが出ました。"Could not find a usable 'nginx' binary. Ensure nginx exists, the binary is executable, and your PATH is set correctly."
この部分ですね。
cronジョブは通常、シェル環境変数を読み込まないため、PATHが設定されていない場合があります。そのため、certbot
コマンドがnginxの実行ファイルを見つけることができていないようです。。
解決するためには、crontabファイルにPATHを明示的に指定するか、certbot
コマンドとnginx
コマンドのフルパスを使用することが必要です。
方法1. crontabにPATHを明示的に指定する(検証済)
今回試したのはこちらです。
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
30 * * * * certbot renew --post-hook "systemctl restart nginx"
環境変数 PATH
の中にnginxの実行ファイルが存在するディレクトリを指定しました。
Mar 19 04:34:12 ip-172-31-24-233 CROND[8269]: (root) CMDOUT (Congratulations, all renewals succeeded: )
Mar 19 04:34:12 ip-172-31-24-233 CROND[8269]: (root) CMDOUT ( /etc/letsencrypt/live/example.com/fullchain.pem (success))
Mar 19 04:34:12 ip-172-31-24-233 CROND[8269]: (root) CMDOUT (- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -)
Mar 19 04:34:12 ip-172-31-24-233 CROND[8269]: (root) CMDOUT (Running post-hook command: systemctl restart nginx)
無事、SSL証明書の更新とnginxの再起動に成功しました。
方法2. crontabにフルパスを指定する
もう1つはPATH変数を宣言せずにcronコマンドに直接パスを指定することでしょう。
30 * * * * /usr/bin/certbot renew --post-hook "/usr/bin/systemctl restart /usr/sbin/nginx"
こちらでも動くはずです。検証はしていません。certbot renewだけでなく、他のコマンドを使用することを想定すると方法1のほうがいいかもしれません。