Fehlermeldung
cURL error 60: SSL certificate problem: unable to get local issuer certificate
Auch ausgegeben als
- 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 formatiert die Meldung als „cURL error 60: SSL certificate problem: <reason> (see https://curl.se/libcurl/c/libcurl-errors.html) for <url>“; ältere Guzzle-Releases verlinkten https://curl.haxx.se/libcurl/c/libcurl-errors.html. Der Grund nach „problem:“ variiert („self-signed certificate in certificate chain“, „certificate has expired“). curl_error() allein liefert den Text nach „cURL error 60: “.
PHP — Guzzle (and Laravel HTTP client, Symfony HttpClient on curl) over ext-curl; curl_errno() 60
Was der Fehler bedeutet
Die curl-Erweiterung von PHP (genutzt von Guzzle, dem HTTP-Client von Laravel und dem curl-Transport von Symfony HttpClient) konnte das Zertifikat des Servers nicht prüfen: libcurl-Fehler 60 mit dem Grund „unable to get local issuer certificate“ von OpenSSL. libcurl hat in seinem Bundle keine CA gefunden, die die Kette des Servers ausgestellt hat. Unter Windows ist das Bundle oft gar nicht konfiguriert; anderswo ist die CA privat, oder der Server lässt ein Zwischenzertifikat weg.
Warum der Fehler auftritt
PHP unter Windows ohne CA-Bundle
häufigPHP-Builds für Windows bringen kein CA-Bundle mit; solange curl.cainfo nicht auf eines verweist (zum Beispiel cacert.pem aus dem curl-Projekt), scheitert jede HTTPS-Anfrage auf diese Weise.
Eine private CA oder ein Proxy mit TLS-Inspektion
häufigBei internen APIs und Verbindungen über einen Proxy endet die Kette bei Root-Zertifikaten, die nicht in dem Bundle stehen, das libcurl verwendet.
Der Server lässt sein Zwischenzertifikat weg
gelegentlichlibcurl mit OpenSSL lädt fehlende Zwischenzertifikate nicht nach.
Container-Images ohne (aktuelle) CA-Zertifikate
gelegentlichEigene PHP-Images, die ohne ca-certificates oder mit einem alten Bundle gebaut wurden, scheitern auch bei öffentlichen Hosts.
So behebst du den Fehler
- 1.
curl.cainfo und openssl.cafile konfigurieren
Setze beide in der php.ini, damit ext-curl und PHP-Streams dasselbe Bundle verwenden; denk daran, dass CLI und PHP-FPM oft unterschiedliche php.ini-Dateien laden.
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.
Guzzle: CA-Bundle an verify übergeben
verify akzeptiert einen Pfad zu einer CA-Datei; Guzzle prüft, ob die Datei existiert, und wirft andernfalls „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.
CA im Zertifikatsspeicher des Systems installieren
Unter Linux verwenden curl und OpenSSL in PHP standardmäßig das Bundle der Distribution; openssl_get_cert_locations() zeigt die Pfade.
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.
Prüfen, welche php.ini gilt
php --ini listet die geladenen Dateien auf; eine Einstellung in der falschen Datei (CLI, FPM oder Apache) bleibt wirkungslos.
bash php --ini # which php.ini files are loaded (CLI and FPM differ!) php -i | grep -E 'curl.cainfo|openssl.cafile'
Verwandte Fehler
cURL error 77: error setting certificate file: /etc/ssl/missing-ca.pemPHP ext-curl (Guzzle, Laravel HTTP client)SSL operation failed with code 1. OpenSSL Error messages:PHP streams (file_get_contents, fopen, stream_socket_client, SoapClient, mail libraries)curl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)