Let's Encrypt証明書の自動更新が止まった:よくある原因と修復チェックリスト
ブラウザに「この接続ではプライバシーが保護されません」と出た、あるいは監視ツールから証明書期限のアラートが届いた——そんな状態でこの記事を開いたのではないでしょうか。Let’s Encryptの証明書は90日で切れる設計なので、自動更新が一度どこかで止まると、忘れた頃に本番で表面化します。ここでは新規取得の手順ではなく、「自動更新が失敗していた」という前提での切り分けと応急処置だけを扱います。
TL;DR
まず状況を数値で把握します。
certbot certificatesで現在の証明書の状態と残り日数を確認するcertbot renew --dry-runで実際に何が失敗するのかをログから特定する- 原因を自動更新の仕組み(cron/systemd timer)→ポート80→DNS認証→レート制限の順にチェックする
- 原因が分かったら手動更新とWebサーバーの再起動で応急処置する
- 二度目を防ぐため、証明書専用の監視を入れる
新規にHTTPS化したい場合はサイトを無料でHTTPSにする方法【Let’s Encrypt + certbot】へ。この記事はセットアップ済みの環境が「動かなくなった」場合の復旧に特化します。
ステップ1:証明書の現状確認
パニックになる前に、まず事実を確認します。
sudo certbot certificates
ドメインごとに Expiry Date と、あと何日で切れるか(VALID: 29 days のような表示)が出ます。ここですでに期限切れ(INVALID: EXPIRED)なのか、まだ猶予があるのかで緊急度が変わります。まだ数日残っているなら、落ち着いて原因調査に時間を使えます。
なお、Let’s Encryptは2025年6月に期限切れ通知メールの送信を廃止しています。以前は公式からのメールで気づけましたが、今は自分で監視するか、たまたま certbot certificates を叩くまで気づけません。この点は再発防止の章で扱います。
ステップ2:手動更新を試してログを読む
次に、実際に更新処理を走らせて何が起きるかを確認します。まず本番の証明書を書き換えない --dry-run で試します。
sudo certbot renew --dry-run
成功すれば The dry run was successful と出ます。失敗する場合は、原因を示すエラーメッセージが標準出力とログの両方に出ます。ログの実体は次のファイルです。
sudo tail -n 100 /var/log/letsencrypt/letsencrypt.log
このログに出てくるキーワードで、次のステップ3のどこを見るべきかがだいたい分かります。
| ログに出るキーワード | 疑うべき原因 |
|---|---|
Timeout during connect | ポート80が塞がっている |
Connection refused | Webサーバーが停止している |
DNS problem | DNS認証(TXTレコード)の失敗 |
too many certificates / rate limit | レート制限への到達 |
| コマンド自体が「command not found」的に失敗 | cron/systemdの実行環境の問題(PATH等) |
ステップ3:よくある原因を順にチェックする
3-1. 自動更新の仕組みが本当に動いているか
「手動で certbot renew を打ったら普通に成功した」場合、証明書取得の仕組み自体でなく、それを定期実行しているcron/systemdの側が止まっていた可能性が高いです。実際、パスが通っていないためにcron実行時だけ失敗する(手元で打つと成功するのに定期実行だけ失敗する)というのは非常によくある事故パターンです。
まずsystemdのタイマーを確認します。
systemctl list-timers | grep certbot
インストール方法によってユニット名が違います。
# apt/dpkgでインストールした場合
sudo systemctl status certbot.timer
sudo journalctl -u certbot.timer --since "7 days ago"
# snapでインストールした場合
sudo systemctl status snap.certbot.renew.timer
inactive や disabled になっていないか、直近の実行(journalctl)がエラーで終わっていないかを見ます。systemd timerが使われていない/存在しない環境では、cronの設定ファイルを直接見ます。
cat /etc/cron.d/certbot
このファイルの中身が想定通りか、実行ユーザーやコマンドパスがおかしくなっていないかを確認してください。cron/systemd timerの仕組み自体を見直したい場合はcronとsystemd timerで定期実行 — バックアップ自動化の基本にも失敗通知の設定まで含めて解説があります。
3-2. ポート80がふさがっていないか
Let’s Encryptの標準認証(HTTP-01)は、更新のたびにポート80への到達性を再確認します。取得時は開いていたのに、後からファイアウォールやセキュリティグループの設定を変えてポート80を閉じてしまい、更新時にだけ失敗するケースがあります。
sudo ufw status
curl -I http://example.com/.well-known/acme-challenge/test
VPSではOS側のファイアウォール(ufw等)に加えて、コントロールパネル側のパケットフィルタ/セキュリティグループでも80番が許可されているか、両方を確認してください。
3-3. DNS認証(DNS-01)を使っている場合はTXTレコードの権限
ワイルドカード証明書などでDNS-01認証を使っている場合、DNSプラグインが使うAPIトークンの有効期限切れ・権限変更が原因になることがあります。TXTレコードの自動登録・削除がプラグイン経由で失敗していないか、DNSプラグインのログ出力を確認してください。
3-4. レート制限に達していないか
短時間に何度も証明書を発行し直そうとすると、Let’s Encrypt側のレート制限に引っかかります。特に同一のドメイン集合に対する重複証明書の発行は週5回までという制限があり、too many certificates already issued for exact set of domains のようなメッセージが出ます。検証環境でやみくもに --force-renewal を繰り返した後などに起きがちです。この場合は待つのが基本の対処で、動作確認だけなら本番証明書を消費しない --dry-run を使ってください。レート制限の詳細な数値は変更されることがあるため、最新の制限値はLet’s Encrypt公式のRate Limitsページで確認するのが確実です。
ステップ4:応急処置
原因が特定できたら、対処してから手動で更新を確定させます。
# 原因を解消したうえで、実際に更新する
sudo certbot renew
# Webサーバーに新しい証明書を読み込ませる
sudo systemctl reload nginx
# または
sudo systemctl reload apache2
reload で反映されない場合は restart を試してください。更新できたかどうかは、外部から接続して証明書の有効期限を直接確認するのが確実です。
curl -vI https://example.com 2>&1 | grep -i "expire\|subject"
--deploy-hook を使っておくと、実際に証明書が更新された回だけ自動でWebサーバーをリロードできるため、今後は「更新はできたのにリロードし忘れて反映されない」という二次トラブルを防げます。
sudo certbot renew --deploy-hook "systemctl reload nginx"
再発防止:証明書専用の監視を入れる
今回、気づくまでに時間がかかったのであれば、証明書の残り日数だけを見張る監視を追加しておくべきタイミングです。前述のとおりLet’s Encrypt自体はもう期限切れメールを送ってくれないため、外形監視の側で検知するしかありません。
外形監視ツールの導入自体はWebサイト死活監視の始め方で解説していますが、多くの監視サービスは「証明書の残り日数がX日を切ったら通知」という設定を単体で持てます。証明書切れ自体は「サイトが完全に落ちる」障害とは性質が違う(HTTPSの警告は出るがHTTPでは繋がる場合もある)ため、通常の死活監視とは別に、この専用アラートを足しておくと安心です。
サイト全体が急に表示されなくなった場合の切り分け手順はサイトが表示されない・繋がらない。いま確認する5つのことにまとめています。証明書以外の原因を疑うときはそちらも参照してください。
まとめ
| ステップ | 確認すること | 使うコマンド |
|---|---|---|
| 1 | 証明書の現状(残り日数) | certbot certificates |
| 2 | 更新処理で何が失敗するか | certbot renew --dry-run / /var/log/letsencrypt/letsencrypt.log |
| 3-1 | 自動更新の仕組みが動いているか | systemctl status certbot.timer / cat /etc/cron.d/certbot |
| 3-2 | ポート80がふさがっていないか | ufw status / セキュリティグループ確認 |
| 3-3 | DNS認証のTXTレコード権限 | DNSプラグインのログ |
| 3-4 | レート制限への到達 | エラーメッセージの rate limit / too many certificates |
| 4 | 応急処置 | certbot renew → systemctl reload nginx |
| 再発防止 | 証明書残り日数の専用監視 | 外形監視ツールの証明書アラート機能 |
自動更新は「一度設定したら忘れていい仕組み」ではなく、「定期的に動いているかを見張る対象」です。今回の対応が終わったら、原因になった箇所(cron/systemd・ファイアウォール・DNSプラグインの認証情報)を記録に残し、同じ理由で再発しないようにしておいてください。