Let's Encryptを使用した証明書の自動更新方法を解説

はじめに

先日、Let's Encryptから以下のメールが届きました。

Let's Encrypt certificate expiration notice for domain "www.example.com"

Hello,

Your certificate (or certificates) for the names listed below will expire in 10 days (on 29 Jan 20 14:00 +0000). Please make sure to renew your certificate before then, or visitors to your website will encounter errors.

We recommend renewing certificates automatically when they have a third of their
total lifetime left. For Let's Encrypt's current 90-day certificates, that means
renewing 30 days before expiration. See
https://letsencrypt.org/docs/integration-guide/ for details.

www.example.com

もうすぐSSL証明書の有効期限が切れるから更新せよ、という内容ですね。

当ポートフォリオサイトだけなら毎回手動で更新してもいいんですが、仕事で作成したWebサイトが他に2つあるので、それらを毎回手動更新するのは大変です。
そこで、Let's EncryptのSSL証明書更新を自動化したのでその手順を残したいと思います。

証明書更新コマンド

まずはコンソールから証明書更新コマンドが正常に実行できるか確認します。
今回は実行日が更新対象外だったため実行がスキップされました。期限日から30日前から更新が可能になります。
なお、オプションで強制的に更新することも可能です。

# /path/to/certbot/certbot-auto renew --post-hook "/sbin/service nginx reload" --webroot -w /var/www/example/current/public -d www.example.com --dry-run

/path/to/certbot/certbot-auto has insecure permissions!
To learn how to fix them, visit https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/www.example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not yet due for renewal

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/www.example.com/fullchain.pem expires on 2020-04-19 (skipped)
No renewals were attempted.
No hooks were run.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

オプションが多いですが、それぞれの意味は以下の通りです。

  • --post-hook:証明書更新コマンド実行後に実行されるコマンドを指定。ここではnginxの再起動を行っている。
  • --webroot -w:Webサイトのドキュメントルートを指定。
    • ドキュメントルート配下の/.well-known/acme-challenge/配下に検証用ファイルを作成する。
    • 一度でもドキュメントルートの指定を行うと、/etc/letsencrypt/renewal/www.example.com.confに設定が書き込まれ、以降は指定しなくても良くなる。
  • --dry-run:テスト実行。実際に証明書は更新されない。

その他のオプションはこちらに解説があります。

自動化設定

/etc/cron.d配下に自動実行用のファイルを作成します。RedHat系のOSではcrontab -eは非推奨とされているため使用しません。

# cd /etc/cron.d
# touch letsencrypt
# vi letsencrypt

0 0 * * * root /path/to/certbot/certbot-auto renew --post-hook "/sbin/service nginx reload" >> /etc/cron.d/letsencrypt.log

毎日0:00に証明書更新コマンドを実行します。3ヶ月に一度実行されればいいだけなので、もっと低頻度でもいいと思います。

実行コマンドは必ずフルパスを指定します。cronの環境変数はコンソール上とは異なるようなので…

念のため実行ログを出力しています(出力先は変えたほうがいいかも…)。

0:00を待ってログを確認してみます。

# cat /etc/cron.d/letsencrypt.log

/home/user/certbot/certbot-auto has insecure permissions!
To learn how to fix them, visit https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/www.example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/www.example.com/fullchain.pem expires on 2020-04-19 (skipped)
No renewals were attempted.
No hooks were run.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# cat /var/log/cron

Jan 21 00:00:01 150-95-152-189 CROND[10332]: (root) CMD (/home/user/certbot/certbot-auto renew --post-hook "/sbin/service nginx reload" >> /etc/cron.d/letsencrypt.log)
Jan 21 00:00:06 150-95-152-189 CROND[10328]: (root) CMDOUT (Saving debug log to /var/log/letsencrypt/letsencrypt.log)
Jan 21 00:00:06 150-95-152-189 CROND[10328]: (root) CMDOUT (Cert not yet due for renewal)

実行されているようです。

まとめ

最初の設定だけ面倒ですが、一度設定してしまえば後は放置していても大丈夫です。
いままで手動更新していた人はこの機会に自動化してみてはいかがでしょうか。