2026年7月17日
2026年7月17日
ApacheのLet’s Encrypt証明書を自動更新する方法(Certbotのタイマー確認と失敗時の対処)
ApacheでLet's Encryptの証明書を使っているなら、Certbotが入れるsystemdのタイマー(またはcron)が1日に数回 certbot renew を実行し、期限が近い証明書だけを更新する仕組みが基本です。自動更新は「設定したつもり」で止まっていることが多いため、この記事では、タイマーが動いているかの確認、--dry-run での更新テスト、更新後にApacheへ新しい証明書を読み込ませる方法、更新に失敗したときの原因の切り分けまでを説明します。
自動更新の仕組み
Let's Encryptの証明書の有効期間は短く、定期的な更新が前提になっています。Certbotは証明書を発行したときの設定を /etc/letsencrypt/renewal/ドメイン名.conf に保存しておき、certbot renew が実行されるたびに、すべての証明書の残り期間を確かめて、更新が必要なものだけを同じ方法で取り直します。
更新するタイミングは、従来は「期限の30日前を切ったら」が既定でした。Let's Encryptは証明書の有効期間をさらに短くしていく方針を発表しており、Certbotの新しい版では、残り期間の割合や、認証局が推奨する更新時期(ACMEのARI)をもとに判断する動きも加わっています(2026年10月現在)。いずれにしても、certbot renew を1日に何度も実行しておけば、更新時期の判断はCertbotに任せられます。
タイマーが動いているか確認する
Certbotの入れ方によって、自動実行の仕組みが異なります。
- snapで入れた場合(Certbotの公式手順で推奨されている方法):
snap.certbot.renew.timerというsystemdのタイマーが作られます。 - aptやdnfのパッケージで入れた場合: 多くの環境で
certbot.timerが作られます。cronの設定(/etc/cron.d/certbot)が一緒に入る環境もありますが、systemdがあるときはタイマー側が使われる作りになっていることが多いです。
次のコマンドで、タイマーが登録され、次の実行予定があるかを確認します。
systemctl list-timers | grep -i certbot
NEXT の列に日時が出ていれば、タイマーは有効です。何も表示されない場合は、タイマーを有効にします。
# snap版
sudo systemctl enable --now snap.certbot.renew.timer
# パッケージ版
sudo systemctl enable --now certbot.timer
前回の実行結果は、サービス側のログで確かめられます。
journalctl -u certbot.service --since "7 days ago" # snap版は snap.certbot.renew.service
ここで気をつけたいのが、snap版とパッケージ版の両方が入っている状態です。どちらの certbot が実行されるかが分かりにくくなり、片方のタイマーだけが古い設定で動くといった混乱の元になります。which -a certbot で複数見つかる場合は、Certbotの公式手順に従って片方を削除し、1つにそろえてください。
更新のテスト(--dry-run)
タイマーが動いていても、更新そのものが成功するとは限りません。テスト用の環境に対して更新の手順だけを実行する --dry-run で確認します。実際の証明書は書き換わりません。
sudo certbot renew --dry-run
最後に、すべての証明書のテストが成功した旨のメッセージが表示されれば問題ありません。失敗した場合は、どの証明書で何が起きたかが表示され、詳しい記録は /var/log/letsencrypt/letsencrypt.log に残ります。
あわせて、手元にある証明書と期限の一覧も見ておきます。
sudo certbot certificates
使っていないドメインの証明書が残っていると、そのドメインの更新が毎回失敗し、ログが見づらくなります。不要なものは sudo certbot delete --cert-name 古いドメイン名 で整理します(どの証明書をApacheが参照しているかを確かめてから行ってください)。
更新後にApacheへ読み込ませる
証明書のファイルが新しくなっても、Apacheが読み込み直さなければ、利用者には古い証明書が送られ続けます。ここが自動更新でつまずきやすいところです。
**Apacheプラグイン(--apache)で発行した場合**は、更新後のApacheの再読み込みもCertbotが行います。更新の設定ファイルを見て、authenticator = apache や installer = apache となっていれば、この方式です。
sudo grep -E "authenticator|installer" /etc/letsencrypt/renewal/example.com.conf
webrootやstandaloneで発行した場合は、Apacheの再読み込みが自動では行われません。更新に成功したときだけ実行される「デプロイフック」を用意します。次のスクリプトを置くと、どの証明書が更新されたときにも実行されます。
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh > /dev/null <<'EOF'
#!/bin/sh
apachectl configtest && systemctl reload apache2
EOF
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh
RHEL系では systemctl reload httpd に読み替えます。configtest を先に通すのは、ほかの設定変更が途中のまま残っていた場合に、再読み込みでApacheが止まるのを避けるためです。再読み込みはグレースフルリスタートなので、処理中のリクエストは切れません。
なお、standaloneはCertbot自身が80番ポートで待ち受ける方式で、Apacheが動いている間は使えません。Apacheを止める前後のフックで回避する方法もありますが、更新のたびにサイトが短時間止まるため、Apacheが動いているサーバーではapacheプラグインかwebrootを使うほうが素直です。
Apacheの設定で参照する証明書のパスは、更新しても変わらない /etc/letsencrypt/live/ドメイン名/ 以下を指定します。Apache 2.4.8以降では、中間証明書を含む fullchain.pem を SSLCertificateFile に指定するのが一般的です。
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
archive 以下のファイルを直接指定すると、更新のたびにファイル名が変わるため、自動更新が反映されなくなります。
更新に失敗するときの原因と確認方法
HTTP-01という一般的な認証方式では、Let's Encryptのサーバーが http://ドメイン名/.well-known/acme-challenge/ にアクセスして、確認用のファイルを読みに来ます。失敗の多くはこの経路のどこかで止まっています。よくある順に確認します。
- 80番ポートが閉じている: HTTPSだけ開けてHTTPを閉じていると、認証が通りません。ファイアウォールやクラウドのセキュリティグループで、80番が外部から開いているかを確認します。HTTPからHTTPSへのリダイレクトは問題ありません。
- DNSが別のサーバーを向いている: サーバー移転後に古いサーバーでCertbotが動いている、IPv6のAAAAレコードだけが古いままになっている、といったケースです。
dig +short A example.comとdig +short AAAA example.comで、両方がこのサーバーを指しているかを確かめます。 - 確認用ファイルへのアクセスが遮られている:
.well-known以下にBasic認証やIP制限がかかっている、セキュリティ系の設定がドットで始まるパスを拒否している、といった原因です。webrootの場合は、renewalの設定にあるwebroot_pathが、実際のDocumentRootと一致しているかも確認します。 - Apacheの設定をCertbotが読み取れない: apacheプラグインは既存の設定を解析して一時的な設定を加えます。1つのファイルに複数のバーチャルホストを書いている、
ServerNameがないといった構成では失敗することがあります。エラーメッセージに出たファイルを確認し、バーチャルホストごとにファイルを分けると解決しやすくなります。 - CDNが前にいる: CloudflareなどのCDNを通している場合、CDNの設定によっては確認用のリクエストがサーバーに届きません。CDN側で
.well-known/acme-challenge/を素通しにするか、DNS-01での認証を検討します。
ワイルドカード証明書はDNS-01でしか発行できず、手動でTXTレコードを書く方式(--manual)では自動更新ができません。自動で更新したい場合は、使っているDNSサービスに対応したCertbotのDNSプラグインを使います。
また、失敗を何度も繰り返すと、Let's Encryptの発行回数の制限に達して、しばらく発行できなくなることがあります。原因を直すまでは --dry-run で試すのが安全です。
実際に配信されている証明書を確かめる
ファイルが更新されたかどうかと、利用者に届いている証明書が新しいかどうかは別の問題です。外部から見える証明書の期限は、次のコマンドで確認できます。
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -enddate
sudo certbot certificates に表示される期限と一致していれば、Apacheは新しい証明書を読み込んでいます。一致しない場合は、Apacheの再読み込みが行われていません。
Let's Encryptは、期限が近づいたことを知らせるメールの送信を2025年に終了しています。以前のように「メールが来たら気づく」という運用はできないため、外部の監視サービスや自前のスクリプトで、上のような期限の確認を定期的に行い、残りが一定の日数を切ったら通知する仕組みを用意しておくと安心です。
まとめ
- 自動更新は、Certbotが入れるsystemdのタイマーが
certbot renewを定期実行する仕組みです。systemctl list-timersで次の実行予定があるかを確認します。 sudo certbot renew --dry-runで、更新そのものが成功するかを定期的に試します。- apacheプラグイン以外で発行した証明書は、デプロイフックで
configtestとsystemctl reloadを実行し、新しい証明書をApacheに読み込ませます。 - 失敗の多くは、80番ポート、DNS、
.well-knownへのアクセス制限、CDNのどこかにあります。ログは/var/log/letsencrypt/letsencrypt.logで確認できます。 - Let's Encryptの期限通知メールは終了しているため、配信中の証明書の期限を外部から監視します。