WordPressで「cURL error 60: SSL certificate problem: unable to get local issuer certificate」を修正する方法

intermediate📝 WordPress2026-05-10| Linux(Ubuntu/CentOS/Debian)上のWordPress 5.x〜6.x、PHP 7.4〜8.3、Apache/Nginx、共有ホスティングまたはVPS

Error Message

cURL error 60: SSL certificate problem: unable to get local issuer certificate
#curl#ssl#証明書#wp-remote-get#https

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:slimalpineのようなスリムベースイメージから構築された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.phpWP_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バンドルを更新できます — 通常数時間以内に対応されます。

Related Error Notes