TL;DR
サーバーにCA(認証局)バンドルファイルが存在しないか古くなっているため、WordPressがリモートサーバーのSSL証明書を検証できません。VPSの場合、CAcertificates パッケージを更新するだけ(約30秒)で恒久的に修正できます。共有ホスティングの場合は、新しいCAバンドルを手動でcURLに指定する必要があります。ローカル開発環境のみ、一時的にSSL検証を無効化する方法も使えます。
原因となるもの
WordPressは常に外部URLを呼び出しています — 決済ゲートウェイ、REST API、ライセンスサーバー、天気情報フィードなどです。各呼び出しはwp_remote_get()またはwp_remote_post()を経由し、内部的にPHPのcURLを使用します。cURLはリモートサーバーのSSL証明書を、サーバーのローカルに保存された信頼済みルートCAリストと照合します。そのリストが古い、存在しない、または間違ったファイルを参照している場合、以下のエラーが発生します:
cURL error 60: SSL certificate problem: unable to get local issuer certificate
よくある原因:
- 最小限のOSイメージでプロビジョニングされたVPS(
ca-certificatesパッケージが未インストール) - 古いCAバンドルを持つ古い共有ホスティング — Let's Encryptのルート証明書は2021年9月に変更され、多くの古いサーバーで問題が発生した
- 誤ったパスまたは存在しない
cacert.pemを指定して--with-curlでコンパイルされたPHP - Windowsベースのローカル開発環境(XAMPPとWAMPにはシステムCAバンドルが同梱されていない)
debian:slimやalpineのようなスリムベースイメージから構築されたDockerコンテナ
まず診断する
やみくもに設定を変更すると時間を無駄にします。CAバンドルの問題なのか、それとも自己署名証明書、リモートURLの破損、PHPの設定の不一致なのかを60秒かけて確認しましょう。
サーバーにSSHで接続して以下を実行します:
curl -v https://api.example.com 2>&1 | grep -E 'SSL|certificate|issuer'
OSレベルでunable to get local issuer certificateが表示された場合、システムCAバンドルが原因です。curlは正常に動作するがWordPressが動作しない場合、PHPのcURLはシステムとは別に設定されています — 参照先を確認しましょう:
php -r "echo curl_version()['ssl_version'];"
php -r "$ch = curl_init('https://api.example.com'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_exec($ch); var_dump(curl_error($ch));"
修正1:システムCA証明書を更新する(VPS / rootアクセス)
サーバーにrootまたはsudoアクセスがある場合、まずこれを実行します。OSレベルで問題を修正するため、WordPressだけでなくサーバー上のすべてのPHPアプリに効果があります。
Ubuntu / Debian:
sudo apt-get update
sudo apt-get install --reinstall ca-certificates
sudo update-ca-certificates
CentOS / RHEL / AlmaLinux:
sudo yum update ca-certificates
# または新しいシステムの場合:
sudo dnf update ca-certificates
更新後、PHP-FPMまたはApacheを再起動して、PHPが更新されたバンドルを読み込むようにします:
# PHP-FPM
sudo systemctl restart php8.1-fpm
# Apache with mod_php
sudo systemctl restart apache2 # Debian/Ubuntu
sudo systemctl restart httpd # CentOS/RHEL
WordPressから失敗していたAPI呼び出しを再度実行して、問題が解決されたことを確認します。
修正2:PHPのcURLを新しいcacert.pemに向ける
rootアクセスがない場合、この方法は共有ホスティング、管理されたコンテナ、システムパッケージに触れられない環境で有効です。
curl.seチームが管理・更新している公式Mozilla CAバンドルを取得します:
cd /path/to/your/wordpress
wget https://curl.se/ca/cacert.pem -O cacert.pem
PHPに使用するよう指定します。php.iniに追加:
[curl]
curl.cainfo = /path/to/your/wordpress/cacert.pem
[openssl]
openssl.cafile = /path/to/your/wordpress/cacert.pem
php.iniを編集できない場合、require行の前に以下をwp-config.phpに追加します:
// cURLを信頼できるCAバンドルに向ける
define( 'CURL_CA_BUNDLE', __DIR__ . '/cacert.pem' );
次に、WordPressのHTTPリクエストにフックするmust-useプラグインを作成します:
<?php
// mu-plugins/fix-curl-ca.php
add_action( 'http_api_curl', function( $handle ) {
if ( defined( 'CURL_CA_BUNDLE' ) && file_exists( CURL_CA_BUNDLE ) ) {
curl_setopt( $handle, CURLOPT_CAINFO, CURL_CA_BUNDLE );
}
} );
修正3:ローカル開発環境のみ — SSL検証を無効化
**本番環境では絶対に使用しないでください。**証明書検証を無効化すると、攻撃者がAPI通信を傍受・改ざんできる中間者攻撃にサイトがさらされます。
開発作業のブロックを解除する必要があるローカルのXAMPP、WAMP、またはDocker環境のみに使用します:
// ローカルのwp-config.phpのみに追加
add_filter( 'https_ssl_verify', '__return_false' );
add_filter( 'https_local_ssl_verify', '__return_false' );
またはAPI呼び出し時に直接指定します:
$response = wp_remote_get( 'https://api.example.com/data', [
'sslverify' => false, // 開発環境のみ!
] );
修正4:リモートサーバーの証明書が問題の場合
問題が自分側にないこともあります。リモートAPIが自己署名証明書または証明書チェーンが不完全な証明書を使用していることがあります。以下で確認します:
openssl s_client -connect api.example.com:443 -showcerts 2>/dev/null | openssl x509 -noout -issuer -subject -dates
発行者とサブジェクトが同一であれば、自己署名証明書です。チェーンが不完全な場合、通常はリモートサーバーに中間証明書が欠けています。対処法:
- APIプロバイダーに連絡する — 証明書の設定が壊れているのは相手側の問題です
- 相手のルート証明書をサーバーのトラストストアに手動で追加する
- 相手の証明書のみを含むファイルを
CURLOPT_CAINFOで指定する(自分で管理する内部APIの場合のみ現実的)
修正を確認する
修正できたと思い込まないようにしましょう。以下のコードを一時的なプラグインまたはテーマのfunctions.phpに貼り付け、管理者としてログインした状態でページを読み込みます:
// このコードを一時的なプラグインまたはテーマのfunctions.phpに一時的に貼り付ける
add_action( 'init', function() {
if ( ! current_user_can( 'manage_options' ) ) return;
$response = wp_remote_get( 'https://api.example.com/endpoint' );
if ( is_wp_error( $response ) ) {
error_log( 'まだ問題があります: ' . $response->get_error_message() );
} else {
error_log( 'HTTPステータス: ' . wp_remote_retrieve_response_code( $response ) );
}
} );
wp-content/debug.logを確認します — まだ有効でない場合はwp-config.phpでWP_DEBUG_LOGを有効にしてください。HTTP 200が返れば完了です。確認後はコードを削除してください。
コマンドラインを好む場合は、PHPのcURLを直接テストします:
php -r "
\$ch = curl_init('https://api.example.com');
curl_setopt(\$ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt(\$ch, CURLOPT_VERBOSE, 1);
curl_exec(\$ch);
echo curl_error(\$ch);
curl_close(\$ch);
"
補足メモ
- curl.seの
cacert.pemは年に数回更新されます。修正2を適用した場合、6ヶ月ごとに再ダウンロードするカレンダーリマインダーを設定してください — 古いバンドルは再び問題を引き起こします。 - Let's Encryptの古いルート証明書(DST Root CA X3)は2021年9月30日に失効しました。Ubuntu 16.04やCentOS 6を実行しているサーバーはこれを唯一の信頼済みLEルートとして持っていたため、その日付前後に多数のLE保護APIが突然失敗し始めました。
- Docker:Dockerfileに
RUN apt-get install -y ca-certificatesを追加してください。debian:slimのようなスリムベースイメージは設計上これを省略しています。 - Cloudways、Kinsta、WP Engine:サポートチケットを開いてください。システムパッケージを自分で更新することはできませんが、運用チームがノードのCAバンドルを更新できます — 通常数時間以内に対応されます。

