Let's Encryptの証明書の自動更新とは、certbot renew をsystemd timer(またはcron)で1日2回動かし、期限が近い証明書だけを更新してWebサーバーに読み込ませる仕組みです。多くの環境ではインストール時にタイマーが入るので、やることは「タイマーの確認」「--dry-run での試験」「nginxをreloadするdeploy-hook」「失敗に気づく仕組み」の4つです。

一方で、Let's Encryptは有効期間を90日から45日へ段階的に短くする計画を発表し、OCSPの終了やARI(CAが更新時期を教える仕組み)も進んでいます。この記事では、letsencrypt.orgの公式発表とcertbotの変更履歴で最新の前提を整理し、certbot 5.8.0・nginx 1.24.0を実際に動かした出力つきで手順を解説します(外部のACMEサーバーに接続できない検証環境のため、証明書の実発行は未実行です。実行結果には「実際の出力」と明記しています)。

certbot自動更新の早見表

やりたいこと コマンド・設定 ポイント
自動更新の確認 systemctl list-timers | grep certbot snap版は snap.certbot.renew.timer、apt版は certbot.timer
更新の予行演習 sudo certbot renew --dry-run ステージングで試すだけ。本番の証明書は変わらない
証明書と期限の一覧 sudo certbot certificates 残り日数(VALID: xx days)が出る
更新後にnginxへ反映 --deploy-hook "nginx -t && systemctl reload nginx" 更新成功時だけ実行
既存証明書の設定変更 sudo certbot reconfigure --cert-name example.com certbot 2.3.0以降
期限が近いか確認 openssl x509 -checkend 1209600 14日以内なら終了コード1
更新タイミング 4.0以降は「残り1/3」、4.1以降はARIに従う 45日証明書にも自動で追従

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Let's Encrypt certbot自動更新|45日化とnginx設定手順」

2026年時点のLet's Encryptの変更点

設定方法は大きく変わりませんが、前提となる証明書の寿命と周辺の仕組みが変わりつつあります。

有効期間は90日→64日→45日へ

日付 内容(公式発表より)
2026年5月13日 45日証明書の tlsserver プロファイルを任意選択で提供開始
2027年2月10日 標準の classic が64日に。認可の再利用期間は10日
2028年2月16日 classic が45日に。認可の再利用期間は7時間

「認可の再利用期間」は、一度成功したドメイン確認(チャレンジ)を使い回せる期間です。現在の30日が最終的に7時間になるため、更新のたびにチャレンジが走る前提で設定しておきます。公式はARI対応クライアントの利用、ARIがない場合は有効期間の約3分の2で更新することを推奨しており、「60日ごと」のような固定間隔では45日証明書に間に合いません。

OCSPは2025年に終了済み

2025年5月7日に証明書からOCSPのURLが削除され、8月6日にOCSPレスポンダーが停止しました(失効情報はCRLで提供)。nginxに ssl_stapling on; が残っていると、次の警告が出ます(OCSPのURLがない証明書での nginx -t の実際の出力)。

[warn] "ssl_stapling" ignored, no OCSP responder URL in the certificate "/etc/t07cert/fullchain1.pem"
nginx: configuration file ... test is successful

ssl_stapling と ssl_stapling_verify の行は削除してかまいません。Must-Staple付きの発行も2025年1月30日から失敗するため、--must-staple も使いません。また、期限切れ通知メールは2025年6月に終了しているので、自分で監視する仕組みが必要です(後述)。

ARI・プロファイル・6日証明書

  • ARI(ACME Renewal Information):CAが「この期間に更新して」と伝える仕組み。CA側の事情で前倒しが必要なときも自動で追従します。
  • プロファイル:classic(標準)、tlsserver(45日)、shortlived(160時間=約6日)から選べます。certbotでは --preferred-profile で指定します。
  • 6日証明書とIPアドレス証明書:2026年1月15日に一般提供開始。IPアドレス証明書は shortlived が必須です。

certbotのバージョンで更新タイミングが変わる

バージョン 自動更新に関わる変更(CHANGELOGより)
2.3.0 certbot reconfigure を追加
4.0.0 「残り30日」固定から「残り1/3」へ。プロファイル指定を追加
4.1.0 ARIに対応
5.0.0 ARIの Retry-After を保存し、確認間隔を守る
5.8.0 2026年9月1日リリース(この記事の検証版)

OS標準パッケージは版が古いことがあります。検証環境(Ubuntu 24.04)で apt-get download certbot を実行すると certbot_2.9.0-1_all.deb が取得され、これはARI非対応・「残り30日で更新」の版です。公式サイトはsnapでのインストールを案内しています。

nginxでの初回取得:--nginx と webroot

方式 コマンド例 向いているケース
nginxプラグイン sudo certbot --nginx -d example.com -d www.example.com nginx設定の書き換えも任せたい
webroot sudo certbot certonly --webroot -w /var/www/letsencrypt -d example.com nginx設定は自分で管理したい
standalone sudo certbot certonly --standalone -d example.com 80番を使うWebサーバーがない

nginx設定を自分で管理しているならwebrootがおすすめです。更新時にnginxを止めず、certbotが設定を書き換えることもありません。80番のserverブロックでチャレンジ用パスだけを返し、他はHTTPSへリダイレクトします。

server {
    listen 80;
    server_name example.com www.example.com;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
        default_type "text/plain";
    }
    location / {
        return 301 https://$host$request_uri;
    }
}

ポートを7070に変えてローカルで動かし、テスト用ファイルを置いて確認しました(実際の出力)。

$ curl -s -i http://127.0.0.1:7070/.well-known/acme-challenge/test-token
HTTP/1.1 200 OK
Content-Type: text/plain

test-token.abc

$ curl -s -i http://127.0.0.1:7070/index.html
HTTP/1.1 301 Moved Permanently

最初はwebrootを作業ディレクトリの下に置いたため403 Forbiddenになりました。エラーログは open() ".../test-token" failed (13: Permission denied) です。nginxのワーカー(www-dataなど)が途中の親ディレクトリに入る権限(x)を持っていなかったのが原因で、namei -m <パス> で確認でき、/var/www/letsencrypt に置き直すと200が返りました。更新時の「Invalid response ... 403」はこのパターンがよくあります。

自動更新が動いているかを確認する

systemctl list-timers | grep certbot
systemctl status snap.certbot.renew.timer   # snap版
systemctl status certbot.timer              # apt版

apt版(2.9.0)に同梱のtimerを展開して確認した実際のファイル内容です。

# /usr/lib/systemd/system/certbot.timer
[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=43200
Persistent=true

# /usr/lib/systemd/system/certbot.service
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot -q renew --no-random-sleep-on-renew
項目 意味
OnCalendar=*-*-* 00,12:00:00 毎日0時と12時
RandomizedDelaySec=43200 最大12時間ずらしてアクセス集中を避ける
Persistent=true 停止中に過ぎた実行を起動後に取り戻す

1日2回動いても、更新が必要な証明書がなければ何もしません。同じパッケージの /etc/cron.d/certbot には test ... -a \! -d /run/systemd/system という条件があり、systemdで動くサーバーではcronではなくtimerが使われます。

手動で certbot renew を実行したときの挙動

期限まで89日の検証用証明書で certbot renew を実行しました(実際の出力、パスは省略)。

An error occurred requesting ACME Renewal Information (ARI). ...
Certificate not yet due for renewal

The following certificates are not due for renewal yet:
  .../live/example.test/fullchain.pem expires on 2026-12-27 (skipped)
No renewals were attempted.

外部接続できない環境なのでARIの取得は失敗していますが、ARIが取れなくても期限にもとづく判断で処理が続くことがわかります。また、更新が必要な状態で非対話(パイプ経由)で実行すると、ログに次の行が出て数分待機しました。

Non-interactive renewal: random delay of 389.241459281269 seconds

certbotは非対話実行時に最大8分のランダム待機を入れます。自作スクリプトで待ちたくない場合は --no-random-sleep-on-renew を付けます(同梱のtimerは付与済み)。

renew --dry-run で予行演習する

sudo certbot renew --dry-run

ステージング環境(テスト用CA)で更新を試し、本番の証明書は保存しません。成功すると Congratulations, all simulated renewals succeeded と表示されます(公式ドキュメントの文言。本環境では未実行)。

挙動 内容
deploy-hook 既定では実行されない。--run-deploy-hooks で実行
ARI certbot 4.1.1以降、dry-run中は確認しない
レート制限 ステージング側を使うので本番の制限を消費しない

deploy-hookでnginxをreloadする

nginxはreloadするまで古い証明書を使い続けます。更新成功時だけreloadするのがdeploy-hookです。

フック 実行タイミング 主な用途
pre-hook 更新を試みる前 standalone方式でnginxを一時停止
deploy-hook 更新に成功した証明書ごと nginxのreload、証明書の配布
post-hook 試行後(成否に関係なく) 停止したnginxの起動

既存の証明書に設定するなら reconfigure が簡単です。nginx -t && を付けると、設定に誤りがあるときはreloadしません。

sudo certbot reconfigure --cert-name example.com \
  --deploy-hook "nginx -t && systemctl reload nginx"

全証明書共通にしたい場合は、フック用ディレクトリに実行権限つきのスクリプトを置きます。

sudo tee /etc/letsencrypt/renewal-hooks/deploy/10-reload-nginx.sh > /dev/null <<'EOF'
#!/bin/sh
set -e
logger -t certbot-deploy "renewed: $RENEWED_LINEAGE ($RENEWED_DOMAINS)"
nginx -t
systemctl reload nginx
EOF
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/10-reload-nginx.sh

renewal設定ファイルの構造

各証明書の設定は /etc/letsencrypt/renewal/<名前>.conf にあります(検証用に作成した例)。

# renew_before_expiry = 30 days
version = 5.8.0
archive_dir = /etc/letsencrypt/archive/example.com
cert = /etc/letsencrypt/live/example.com/cert.pem
privkey = /etc/letsencrypt/live/example.com/privkey.pem
chain = /etc/letsencrypt/live/example.com/chain.pem
fullchain = /etc/letsencrypt/live/example.com/fullchain.pem

[renewalparams]
authenticator = webroot
server = https://acme-v02.api.letsencrypt.org/directory
key_type = ecdsa
deploy_hook = nginx -t && systemctl reload nginx
[[webroot_map]]
example.com = /var/www/letsencrypt

renew_before_expiry はコメントのままがおすすめです。有効にすると「残り1/3」の既定やARIより優先されます。

また、検証で fullchain.pem を cert.pem と同じ内容にしたところ、次のエラーでスキップされました(実際の出力)。live/ や archive/ を手で編集・コピーするとこうなるので、移行時は /etc/letsencrypt を丸ごと移します。

Renewal configuration file .../renewal/example.test.conf produced an unexpected error: fullchain does not match cert + chain for example.test!. Skipping.

更新失敗に気づく仕組み

期限が近い状態・アカウント情報なしで certbot renew を実行すると、次のように失敗し終了コードは1でした(実際の出力)。

Failed to renew certificate example.test with error: Account at .../accounts/... does not exist
All renewals failed. The following certificates could not be renewed:
  .../live/example.test/fullchain.pem (failure)
1 renew failure(s), 0 parse failure(s)

終了コードが0以外になるので、systemdの OnFailure= で通知できます(通知用の notify-failure@.service は別途用意します)。

# sudo systemctl edit certbot.service(snap版は snap.certbot.renew.service)
[Unit]
OnFailure=notify-failure@%n.service

証明書ファイルの期限は openssl で確認できます(検証用証明書での実際の出力)。

$ openssl x509 -in fullchain.pem -noout -enddate
notAfter=Dec 27 15:47:23 2026 GMT
$ openssl x509 -in fullchain.pem -noout -checkend $((14*86400))
Certificate will not expire
監視の方法 検知できること
OnFailure= で通知 certbotの実行失敗
openssl -checkend を定期実行 更新されずに期限が近づいている
外形監視で公開中の証明書期限を確認 ファイルは新しいのにreloadされていない

3つ目がとくに大切です。45日証明書では残り10日前後で警告するのがちょうどよい目安です。

よくあるエラーと対処

エラー・症状 主な原因 対処
Invalid response ... 404 webrootとnginxの root がずれている パスを合わせ、テストファイルをcurlで確認
Invalid response ... 403 親ディレクトリに実行権限がない namei -m で確認し /var/www 配下へ
Timeout during connect (likely firewall problem) 80番が閉じている 80番を開ける。難しければDNS-01
too many certificates already issued 同じ証明書を短期間に何度も発行 試験は --dry-run で行う
fullchain does not match cert + chain live/ を手で編集・コピー /etc/letsencrypt を丸ごと復元
Account at ... does not exist 移行時に accounts/ を移していない /etc/letsencrypt 全体を移す
更新済みなのにブラウザの期限が古い reload漏れ deploy-hookを設定

45日時代の設定チェックリスト

  • [ ] certbot --version が4.1以降(ARI対応)
  • [ ] systemctl list-timers にcertbotのタイマーがある
  • [ ] renew_before_expiry を固定値で上書きしていない
  • [ ] sudo certbot renew --dry-run が成功する
  • [ ] deploy-hookで nginx -t && systemctl reload nginx を設定済み
  • [ ] ssl_stapling などOCSP関連の設定を外した
  • [ ] 失敗通知と、公開中の証明書期限の外形監視がある

よくある質問

Q. 自動更新の設定は自分で追加する必要がありますか? A. snap版・apt版はインストール時にtimerが入ります。まず systemctl list-timers で確認し、あれば追加は不要です。pipで入れた場合は自分でtimerかcronを用意します。

Q. 45日化に向けて今すぐ変えることはありますか? A. classic が短くなるのは2027年2月10日(64日)と2028年2月16日(45日)です。ARI対応のcertbotを既定の更新タイミングで動かしていれば、追加作業はほとんどありません。先に試すなら --preferred-profile tlsserver で45日証明書を選べます。

Q. 1日2回の実行でレート制限に引っかかりませんか? A. certbot renew は更新が必要な証明書しか要求しないため、それ以外の実行ではCAに証明書を求めません。Let's Encryptも、45日化で更新が増えてもレート制限の変更は不要と説明しています。

Q. deploy-hookとpost-hookはどちらを使えばよいですか? A. nginxのreloadならdeploy-hookです。post-hookは成否に関係なく毎回動くので、standalone方式で止めたnginxの再起動に向いています。

まとめ

  • 自動更新は certbot renew を1日2回動かす仕組み。多くの環境ではtimerが最初から入っている
  • 有効期間は2027年2月に64日、2028年2月に45日へ。固定間隔ではなく「残り1/3」かARIで更新する
  • certbot 4.1以降はARI対応。OS標準パッケージの版を certbot --version で確認する
  • nginxはwebroot方式+deploy-hook(nginx -t && systemctl reload nginx)が扱いやすい
  • OCSPは2025年8月に終了。ssl_stapling の設定は外してよい
  • 設定変更後は --dry-run、運用では失敗通知と外形監視をセットにする

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Let's Encrypt certbot自動更新|45日化とnginx設定手順」

株式会社RJCでは、証明書の更新のような「止めないための運用」を、プロジェクトの中で仲間と確かめ合いながら身につけています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?