Ffile2fix
Sign in Get started

How to fix cURL error 60: unable to get local issuer certificate

cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)

cURL could not build a trusted chain from the remote server's certificate to a root certificate authority in its CA bundle, so it refused the HTTPS connection. Either your machine's CA bundle is missing or outdated, or the remote server is not sending its intermediate certificate.

Also appears as: curl: (60) SSL certificate problem: unable to get local issuer certificate · cURL error 60: SSL certificate problem: certificate has expired · cURL error 60: SSL certificate problem: self signed certificate in certificate chain · GuzzleHttp\Exception\RequestException: cURL error 60: SSL certificate problem: unable to get local issuer certificate

Common causes

  • PHP on Windows (XAMPP, WAMP, Laragon) has no CA bundle configured in curl.cainfo or openssl.cafile
  • An outdated ca-certificates package on an old Linux server that lacks newer root certificates
  • The remote server sends only its leaf certificate without the intermediate chain (use fullchain.pem, not cert.pem)
  • A corporate proxy or antivirus intercepts HTTPS with its own root certificate that PHP does not trust
  • The remote certificate is self-signed or expired
  • A Docker image built without the ca-certificates package

How to fix it

  1. Find which side is wrong. Check the remote site with an SSL checker or openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts. If the chain is incomplete there, the remote server must fix it; if it is complete, your client's CA bundle is the problem.
  2. Update the system CA bundle (Linux). Run sudo apt update && sudo apt install --reinstall ca-certificates (Debian/Ubuntu) or sudo dnf update ca-certificates (RHEL), or add apk add ca-certificates in Alpine Docker images.
  3. Set curl.cainfo in php.ini (Windows/local). Download the current cacert.pem from the curl website, save it to a stable path, and set curl.cainfo and openssl.cafile to that path in the php.ini used by your PHP (check with php --ini). Restart Apache or PHP-FPM.
  4. Fix the chain on your own server. If the failing URL is your own site, configure the web server with the full chain (fullchain.pem or the CA bundle file) instead of just the certificate.
  5. Trust a corporate root properly. If a company proxy intercepts traffic, add its root certificate to the system trust store and update-ca-certificates rather than disabling verification.
  6. Never disable verification. Setting CURLOPT_SSL_VERIFYPEER to false or 'verify' => false in Guzzle makes the error go away by removing protection against man-in-the-middle attacks. Do not use it in production.

php.ini (Windows / local dev)

[curl]
curl.cainfo = "C:\php\extras\ssl\cacert.pem"

[openssl]
openssl.cafile = "C:\php\extras\ssl\cacert.pem"

; Linux: sudo apt install --reinstall ca-certificates

How to stop it happening again

  • Keep ca-certificates updated as part of normal OS updates
  • Include ca-certificates in every Docker base image
  • Always serve fullchain certificates on your own servers

Frequently asked questions

Is it safe to set verify to false to fix cURL error 60?

No. It disables certificate checking, so your server will accept any certificate including an attacker's. Fix the CA bundle or the remote chain instead.

Why does the URL open fine in my browser?

Browsers ship their own up-to-date root stores and can fetch missing intermediates. cURL and PHP rely on the CA bundle on your machine and do not fetch missing intermediates.

I edited php.ini but nothing changed. Why?

PHP often has separate php.ini files for CLI and the web server. Run php --ini and check phpinfo() in the browser to edit the right files, then restart the web server or PHP-FPM.