エラーメッセージ
curl: (60) SSL certificate problem: certificate has expired
別の表記
- curl: (60) SSL certificate OpenSSL verify result: certificate has expired (10)
理由のテキストは、OpenSSL 1.1.1、3.0、3.5 でビルドされた curl で同じです。新しい curl のリリース(ecdsa.com のテストでは 8.22.0)では「SSL certificate OpenSSL verify result: certificate has expired (10)」と表記されます。まだ有効ではない証明書の場合は、「certificate is not yet valid」という別の理由になります。
curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_CERT_HAS_EXPIRED (10)
このエラーの意味
curl が構築したチェーン内のいずれかの証明書で、notAfter の日付が curl を実行しているマシンの現在時刻より前になっています。通常はサーバー自身の証明書ですが、期限切れの中間証明書やクロス署名されたルートでも同じメッセージになります。チェックはローカルの時計を基準に行われるため、時計がずれていると、証明書の期限切れとまったく同じように見えます。
発生する理由
自動更新が機能しなくなった
よくある一度も有効化されていない certbot のタイマー、CDN やファイアウォールの背後で失敗するようになった ACME チャレンジ、期限切れになった DNS API トークン、担当者のいない手動の手順などが原因です。公開証明書の有効期間は 2026年に 200 日、2029年までに 47 日へと短縮されるため、気づかれない更新の失敗はすぐに表面化します。
証明書は更新されたが、サーバーがまだ古い証明書を返している
よくあるnginx、HAProxy、Postfix、Java のサーバーは、起動時に証明書を読み込みます。ディスク上のファイルを更新しても、プロセスがリロードするまでは何も変わりません。ロードバランサーや CDN は、アップロードされた独自のコピーを保持しています。
返されるチェーン内の中間証明書またはクロス署名証明書が期限切れになっている
ときどき古い中間証明書(たとえば、古い fullchain からコピーしたクロス署名の中間証明書)を同梱しているサーバーでは、リーフ証明書が有効期間内であっても、クライアントが期限切れの証明書を経由するパスを構築してしまうことがあります。2021年に DST Root CA X3 のクロス署名が期限切れになった際には、多くの古いクライアントがこの形で動作しなくなりました。
クライアントの時計がずれている
ときどきバッテリーでバックアップされた時計を持たないデバイス、スナップショットから復元した VM、時刻がずれていくホスト上のコンテナーでは、時計が数か月ずれていることもあります。すべての HTTPS サイトで同時に失敗する場合は、何よりも先に日付を確認してください。
古いクライアントが期限切れのルートへのパスを構築する
まれCA バンドルが古いクライアントは、ルートの期限切れのバージョンしか知らず、最新のクライアントがより新しいパスを選ぶ場合でも失敗することがあります。ca-certificates を更新すれば解決します。
修正方法
- 1.
期限切れの証明書を特定する
サーバーが送信するすべての証明書について、notAfter の日付を表示してください。リーフ証明書が期限切れなら更新し、中間証明書が期限切れなら、チェーンファイルを CA が現在公開しているものに置き換えてください。
bash # Split the served chain into cert1.pem (leaf), cert2.pem, ... and print each expiry date openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | awk '/BEGIN CERT/{n++; f="cert" n ".pem"} /BEGIN CERT/,/END CERT/{print > f}' for f in cert*.pem; do openssl x509 -in "$f" -noout -subject -enddate; done - 2.
更新してリロードし、実際に返される証明書を確認する
更新後は、その名前の TLS を終端するすべてのプロセスと機器をリロードし、ディスク上のファイルではなくネットワーク側から日付を確認してください。
bash sudo certbot renew # or your ACME client / CA portal sudo systemctl reload nginx # the server keeps serving the old file until reloaded echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -enddate # confirm the new date is what the network sees - 3.
クライアントの時計を修正する
ほかのマシンでは証明書に問題がない場合は、失敗しているマシンの時刻を NTP で同期してください。コンテナーの時計はホストから提供されるため、ホスト側で修正してください。
bash date -u # compare with the real UTC time timedatectl status # "System clock synchronized: yes"? sudo timedatectl set-ntp true - 4.
クライアントの CA バンドルを更新する
長期間稼働しているシステムでは、ca-certificates パッケージを更新すると、廃止されたルートが削除され、現行のルートが追加されます。これにより、OpenSSL は期限切れのパスではなく有効なパスを選べるようになります。
bash # Old clients: refresh the root store so they stop building paths through retired roots sudo apt-get update && sudo apt-get install --only-upgrade ca-certificates # Debian/Ubuntu sudo dnf upgrade ca-certificates # RHEL/Fedora
関連するエラー
verify error:num=10:certificate has expiredOpenSSL CLI (openssl s_client / openssl verify)x509: certificate has expired or is not yet valid: current time 2026-08-20T15:4…Go crypto/x509certificate has expiredNode.js tls / https / fetch[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate has exp…Python ssl module (OpenSSL)curl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)