2026年9月28日
2026年9月28日
WordPressの「certificate has expired」エラーを解決する方法|サイトの証明書切れと外部通信のエラーを切り分ける
WordPress で「certificate has expired」と表示されたときは、まず「訪問者のブラウザが自分のサイトの証明書切れを警告している」のか、「WordPress(サーバー)が外部へ通信したときに相手の証明書を検証できなかった」のかを切り分けます。前者は証明書の更新と Web サーバーの再読み込みで、後者はサーバーの CA 証明書・WordPress 本体の更新や時刻の確認で解決することがほとんどです。この記事では、表示されている場所からどちらかを判断し、原因の可能性が高い順に確認と対処の方法を説明します。
まず、どこにエラーが出ているかを確認する
同じ「期限切れ」でも、出る場所によって原因がまったく異なります。
- ブラウザでサイトを開くと警告が出る:Chrome では
NET::ERR_CERT_DATE_INVALID、Firefox ではSEC_ERROR_EXPIRED_CERTIFICATEなどと表示されます。自分のサイトの証明書(または途中の中間証明書)が期限切れです。→「ケースA」へ - WordPress の管理画面やログに出る:プラグインの更新時、サイトヘルスの検査、外部 API と連携するプラグインのエラーなどで
cURL error 60: SSL certificate problem: certificate has expiredと表示されます。サーバーから外へ出る通信で、相手の証明書を検証できていません。→「ケースB」へ
ケースBでは、ブラウザから見たサイト自体は正常に表示されていることがよくあります。サイトヘルスの「ループバックリクエスト」や「REST API」の項目でこのエラーが出ている場合は、WordPress が自分自身の URL にアクセスして失敗しているので、ケースAとケースBの両方を確認します。
証明書の有効期限を正確に確かめる
ブラウザの表示だけでなく、コマンドで実際にサーバーが返している証明書を確認します。CDN を使っている場合、ブラウザが見ているのは CDN の証明書で、サーバー本体の証明書とは別物である点に注意してください。
# サーバーが返している証明書の有効期限・発行者・対象を表示
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -dates -issuer -subject
# 証明書チェーン全体(中間証明書を含む)を確認
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null
notAfter= が有効期限です。-servername を付けないと、複数のサイトを載せたサーバーでは別のサイトの証明書が返ることがあるため、付けて確認します。
ケースA:自分のサイトの証明書が期限切れ(可能性の高い順)
1. 自動更新が止まっている
Let's Encrypt の証明書は有効期間が短く、自動更新を前提にしています。certbot を使っている場合は、次のコマンドで状態を確認できます。
sudo certbot certificates # 管理中の証明書と期限の一覧
sudo certbot renew --dry-run # 更新を試験的に実行(実際の証明書は変わらない)
systemctl list-timers | grep -i certbot # 自動更新のタイマーが動いているか
--dry-run が失敗する場合、その出力に原因が表示されます。よくあるのは次のものです。
- ドメインの DNS(A レコード・AAAA レコード)が別のサーバーを向いている。特に、AAAA レコードだけが古いサーバーを指しているケースは見落としがちです
- 80番ポートがファイアウォールで閉じている、または .htaccess やセキュリティ系プラグインの設定で
/.well-known/acme-challenge/へのアクセスが拒否されている - CAA レコードで Let's Encrypt 以外の認証局しか許可していない
原因を直したら sudo certbot renew で更新します。
2. 更新はできたが Web サーバーが古い証明書を使い続けている
certbot が新しい証明書を取得しても、Apache や nginx を再読み込みしないと古い証明書のまま配信されます。certbot certificates では期限が先なのに、openssl s_client では期限切れが返る場合はこれが原因です。
sudo nginx -t && sudo systemctl reload nginx
# Apache の場合
sudo apachectl configtest && sudo systemctl reload apache2
今後も同じことが起きないよう、更新が成功したときに再読み込みするフックを用意します。certbot は /etc/letsencrypt/renewal-hooks/deploy/ に置いた実行可能なスクリプトを、証明書の更新後に実行します。
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-web.sh >/dev/null <<'EOF'
#!/bin/sh
systemctl reload nginx
EOF
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-web.sh
Apache を使っている場合は systemctl reload apache2(RHEL 系では httpd)に書き換えます。certbot --nginx や --apache で取得した証明書は再読み込みまで自動で行われることが多いものの、--webroot や certonly で取得した場合は再読み込みされないため、このフックが役に立ちます。
3. 設定ファイルが別の(古い)証明書ファイルを指している
手動で証明書を設置した過去がある場合、設定ファイルの ssl_certificate(nginx)や SSLCertificateFile(Apache)が古いファイルを指したままのことがあります。Let's Encrypt の場合は /etc/letsencrypt/live/ドメイン名/fullchain.pem を指すのが基本です。cert.pem だけを指定していると中間証明書が送られず、一部の環境でエラーになります。
4. レンタルサーバーや CDN の無料 SSL の更新失敗
共用のレンタルサーバーでは、管理画面の SSL 設定で証明書の状態と期限を確認できます。ドメインのネームサーバーを他社に移した、CDN を挟んだなどの理由で自動更新が失敗していることがあります。CDN を使っている場合は、CDN の管理画面でエッジ証明書の状態を、オリジン(サーバー本体)側でオリジン証明書の期限を、それぞれ確認してください。
ケースB:WordPress から外部への通信で期限切れになる(可能性の高い順)
1. サーバーの CA 証明書が古い
相手のサイトの証明書が有効でも、サーバー側が持つ信頼済みのルート証明書が古いと、検証の途中で期限切れの証明書をたどってしまうことがあります。2021年に Let's Encrypt の古いルート証明書が期限切れになった際には、古い OS や OpenSSL を使うサーバーでこのエラーが多発しました。
# Debian / Ubuntu
sudo apt update && sudo apt install --only-upgrade ca-certificates
# RHEL 系
sudo dnf update ca-certificates
PHP がどの CA ファイルを参照しているかは、php -r 'var_dump(openssl_get_cert_locations());' で確認できます。php.ini の curl.cainfo や openssl.cafile に古いファイルが指定されていないかも見ておきます。
2. WordPress 本体が古い
WordPress の HTTP API は、本体に同梱された CA 証明書のバンドル(wp-includes/certificates/ca-bundle.crt)を使って相手の証明書を検証します。このファイルは WordPress の更新で新しくなるため、本体が古いままだと検証に失敗することがあります。管理画面から更新できない場合は、WP-CLI の wp core update を使うか、手動で更新します。作業前にはバックアップを取ってください。
3. サーバーの時刻がずれている
サーバーの時計が未来の日付にずれていると、有効な証明書でも期限切れと判定されます。timedatectl で時刻と NTP の同期状態を確認し、同期が無効なら sudo timedatectl set-ntp true で有効にします。
4. 通信先の証明書が本当に期限切れ
プラグインが連携している外部サービス側の証明書が切れている場合、こちらでは直せません。openssl s_client で相手のドメインを確認し、期限切れであればプラグインの開発元やサービスの運営者に連絡します。
修正後は、WP-CLI で実際に通信できるかを確認します。
wp eval 'var_dump( wp_remote_retrieve_response_code( wp_remote_get( "https://api.wordpress.org/" ) ) );'
200 などのステータスコードが返れば通信できています。エラーの場合は WP_Error の内容が表示されます。
証明書の検証を無効にする回避策は使わない
検索すると、https_ssl_verify フィルターで false を返したり、sslverify を無効にしたりする方法が見つかります。これは証明書の検証そのものをやめる操作で、通信相手のなりすましを見抜けなくなります。一時的な切り分けでステージング環境に限って試すことはあっても、本番環境で恒常的に使う対処ではありません。
再発を防ぐ
- 証明書の期限を外部から監視する仕組みを用意する。Let's Encrypt は2025年に期限切れ通知メールの送信を終了したため、通知メールに頼った運用は見直しが必要です
- 証明書の有効期間は業界全体で短くなる方向にあるため(2026年10月現在)、手動更新の運用は避け、自動更新と再読み込みのフックをそろえておく
- OS のパッケージと WordPress 本体を定期的に更新し、CA 証明書を新しく保つ
まとめ
- ブラウザの警告なら自分の証明書、
cURL error 60なら外部通信の検証失敗と、出る場所で切り分ける openssl s_client -servernameで実際に返っている証明書の期限とチェーンを確かめる- ケースAは自動更新の失敗と Web サーバーの再読み込み漏れが多く、
certbot renew --dry-runとデプロイフックで対処する - ケースBは CA 証明書・WordPress 本体の更新とサーバー時刻の確認で解決することが多い
- 証明書の検証を無効にする回避策は使わず、期限の外部監視で再発を防ぐ