本文へスキップ
ecdsa.com
PHPPHP

エラーメッセージ

cURL error 60: SSL certificate problem: unable to get local issuer certificate

別の表記

  • GuzzleHttp\Exception\ConnectException: cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.se/libcurl/c/libcurl-errors.html) for https://api.example.com:8443/

Guzzle はこれを「cURL error 60: SSL certificate problem: <reason> (see https://curl.se/libcurl/c/libcurl-errors.html) for <url>」という形式で出力します。古い Guzzle のリリースでは https://curl.haxx.se/libcurl/c/libcurl-errors.html にリンクしていました。「problem:」の後の理由は状況によって異なります(「self-signed certificate in certificate chain」「certificate has expired」など)。curl_error() 単体では、「cURL error 60:」の後のテキストが返されます。

PHP — Guzzle (and Laravel HTTP client, Symfony HttpClient on curl) over ext-curl; curl_errno() 60

このエラーの意味

PHP の curl 拡張(Guzzle、Laravel の HTTP クライアント、Symfony HttpClient の curl トランスポートが使用)が、サーバーの証明書を検証できませんでした。libcurl のエラー 60 で、OpenSSL の理由は「unable to get local issuer certificate」です。libcurl のバンドルの中に、サーバーのチェーンを発行した CA が見つかりませんでした。Windows ではバンドルがまったく設定されていないことがよくあります。それ以外の環境では、CA がプライベートなものであるか、サーバーが中間証明書を送信していないかのどちらかです。

発生する理由

修正方法

  1. 1.

    curl.cainfo と openssl.cafile を設定する

    ext-curl と PHP のストリームが同じバンドルを使うように、php.ini で両方を設定してください。CLI と PHP-FPM では、読み込まれる php.ini ファイルが異なることが多い点に注意してください。

    ini
    ; php.ini — CA bundle for ext-curl (Guzzle, Laravel Http, Symfony HttpClient) and for streams
    curl.cainfo = "/etc/ssl/certs/ca-certificates.crt"
    openssl.cafile = "/etc/ssl/certs/ca-certificates.crt"
    ; Windows: download cacert.pem from https://curl.se/docs/caextract.html and use its full path
  2. 2.

    Guzzle:verify に CA バンドルを渡す

    verify には CA ファイルのパスを指定できます。Guzzle はファイルが存在するかをチェックし、存在しなければ「SSL CA bundle not found」というエラーを発生させます。

    php
    // Trust a private CA for one client: verify takes a CA bundle path
    $client = new GuzzleHttp\Client(['verify' => '/etc/ssl/private-ca/corp-root-ca.pem']);
    $response = $client->get('https://api.example.com/');
  3. 3.

    CA をシステムのストアにインストールする

    Linux では、PHP の curl と OpenSSL はデフォルトでディストリビューションのバンドルを使います。パスは openssl_get_cert_locations() で確認できます。

    bash
    # Debian/Ubuntu-based PHP images: install the root, then check what PHP uses
    cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt && update-ca-certificates
    php -r 'var_dump(openssl_get_cert_locations()); echo ini_get("curl.cainfo"), PHP_EOL;'
  4. 4.

    どの php.ini が有効になっているかを確認する

    php --ini で、読み込まれているファイルが一覧表示されます。間違ったファイル(CLI 用、FPM 用、Apache 用の取り違え)に追加した設定は効果がありません。

    bash
    php --ini                        # which php.ini files are loaded (CLI and FPM differ!)
    php -i | grep -E 'curl.cainfo|openssl.cafile'

関連するエラー

署名エラーデータベースをすべて見る