SSL Errors with cURL and PHP

Diagnose and fix SSL problems in your PHP applications.

SSL errors with cURL are among the most frustrating for PHP developers. "SSL certificate problem: unable to get local issuer certificate" is the classic message.

These errors often occur after a server migration, PHP update, or when integrating third-party APIs.

This guide covers causes and solutions for the most common cURL SSL errors.

Common Errors

Typical cURL SSL error messages:

  • unable to get local issuer: the root certificate bundle is not found or configured.
  • certificate verify failed: the server's certificate cannot be verified.
  • self signed certificate: the server uses an unrecognized self-signed certificate.
  • certificate has expired: the remote server's certificate has expired.

Main Causes

Why these errors occur:

  • Missing CA bundle: PHP/cURL cannot find the cacert.pem file.
  • PHP configuration: curl.cainfo or openssl.cafile not configured.
  • Remote server: incomplete certificate chain on the remote server.
  • Proxy/Firewall: a proxy intercepts and modifies SSL connections.

Solutions

How to resolve these errors:

  1. Download CA bundle: get cacert.pem from curl.se.
  2. Configure PHP: add the path in php.ini.
  3. Test configuration: verify with a test script.
  4. Debug if needed: use CURLOPT_VERBOSE for more info.

Code Solutions

Fixes for cURL SSL errors:

<?php
// Solution 1: Specify CA bundle in code
$ch = curl_init("https://api.example.com");
curl_setopt($ch, CURLOPT_CAINFO, "/path/to/cacert.pem");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

// Solution 2: Configure in php.ini
// curl.cainfo = "/path/to/cacert.pem"
// openssl.cafile = "/path/to/cacert.pem"

// BAD PRACTICE - DO NOT DO IN PRODUCTION
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

// Debug
curl_setopt($ch, CURLOPT_VERBOSE, true);
$verbose = fopen("php://temp", "w+");
curl_setopt($ch, CURLOPT_STDERR, $verbose);

Download cacert.pem: https://curl.se/docs/caextract.html

Best Practices

Avoid common pitfalls:

  • Never VERIFYPEER false: disabling SSL verification exposes to MITM attacks.
  • Update the bundle: the CA bundle should be updated regularly.
  • Configure globally: configure in php.ini rather than each script.
  • Test in staging: verify SSL connections before production.

Debug Checklist

  • cacert.pem downloaded and up to date
  • php.ini configured
  • Bundle path verified
  • Remote server tested (complete chain)
  • Proxy/firewall checked
  • CURLOPT_VERBOSE enabled if needed

Frequently Asked Questions

Can I disable SSL verification?

Only in development. NEVER in production, it exposes to MITM attacks.

Where to find cacert.pem?

curl.se/docs/caextract.html - it's the official Mozilla bundle.

Is the error from the remote server?

Possibly. Test with SSL Labs if it's a third-party server.

It worked and now it doesn't?

PHP update, server change, or remote certificate expiration.

Guzzle has the same issue?

Yes, Guzzle uses cURL. Same solution: configure the CA bundle.

How to automate bundle updates?

Create a cron that downloads cacert.pem periodically from curl.se.

Pain-Free cURL SSL

cURL SSL errors are solved by correctly configuring the CA certificate bundle. Never disable verification.

Monitor your own certificates with MoniTao to avoid being the source of the problem for your clients.

Ready to Sleep Soundly?

Start free, no credit card required.