How7o
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Reading: How to Fix cURL Error 60 SSL Certificate Problem in Laravel
Share
How7oHow7o
Font ResizerAa
  • OS
Search
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Follow US
© 2024–2026 How7o. All rights reserved.
How7o > Free Laravel, PHP, WordPress & Server Tutorials > Web Development > How to Fix cURL Error 60 SSL Certificate Problem in Laravel
Web Development

How to Fix cURL Error 60 SSL Certificate Problem in Laravel

how7o
By how7o
Last updated: May 10, 2026
9 Min Read
Laravel cURL error 60 SSL certificate problem — CA bundle wiring in php.ini
SHARE

The laravel curl error 60 — SSL certificate problem: unable to get local issuer certificate, sometimes certificate has expired — is a PHP-level trust error that shows up whenever Laravel’s HTTP client (Guzzle under the hood) makes an outbound HTTPS call. The proper fix is to point your php.ini at a current CA bundle. The common “'verify' => false” workaround disables TLS validation on every affected request and should stay out of production.

Contents
  • TL;DR
  • Why the error happens
  • Fix 1 — Point PHP at a fresh CA bundle (recommended)
  • Fix 2 — Per-request 'verify' => false (local only)
  • What not to do — edit vendor/guzzlehttp/
  • If it’s “certificate has expired”
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-04-23 on Laravel 11 with PHP 8.3 and Guzzle 7. Originally published 2023-04-25, rewritten and updated 2026-04-23.

TL;DR

Download the Mozilla CA bundle from curl.se/docs/caextract.html, save it as cacert.pem, and wire it into both OpenSSL and curl in php.ini:

openssl.cafile = "/etc/ssl/certs/cacert.pem"
curl.cainfo    = "/etc/ssl/certs/cacert.pem"

Restart PHP-FPM (or Apache with mod_php) for the change to take effect. 'verify' => false is only safe for local-only debugging.

Why the error happens

When Guzzle makes an HTTPS request, libcurl (or the stream wrapper) asks OpenSSL to verify the remote server’s certificate chain against a list of trusted Certificate Authorities. That list comes from a CA bundle on disk. If the CA bundle path isn’t configured in php.ini, or the file it points to is missing or outdated, verification fails with cURL error 60 — even though the remote server’s certificate is valid.

On most Linux distributions with a default php package the CA bundle is wired up automatically (openssl.cafile points at the system cert store at /etc/ssl/certs/). On Windows, minimal Docker images, and stripped-down VPS setups, the setting is often blank — which is exactly when cURL error 60 starts appearing in production.

Fix 1 — Point PHP at a fresh CA bundle (recommended)

  1. Download the current CA bundle from curl.se/docs/caextract.html. The file is called cacert.pem.
  2. Save it to a stable path on the server — /etc/ssl/certs/cacert.pem on Linux, C:\php\extras\ssl\cacert.pem on Windows.
  3. Open php.ini (php --ini tells you which file is loaded).
  4. Find the ;curl.cainfo and ;openssl.cafile lines, uncomment them by removing the leading semicolon, and set the path:
; php.ini — Linux paths
openssl.cafile = "/etc/ssl/certs/cacert.pem"
curl.cainfo    = "/etc/ssl/certs/cacert.pem"

; Windows paths — use forward slashes or escaped backslashes
openssl.cafile = "C:/php/extras/ssl/cacert.pem"
curl.cainfo    = "C:/php/extras/ssl/cacert.pem"
  1. Restart your PHP process so the new php.ini is loaded: sudo systemctl restart php8.3-fpm on Linux with PHP-FPM, sudo systemctl restart apache2 on Apache with mod_php, or restart the Windows service / IIS app pool.
  2. Verify the setting is live: php -r 'echo ini_get("curl.cainfo"), PHP_EOL, ini_get("openssl.cafile"), PHP_EOL;' should print your path twice.

That’s the fix. Every Guzzle / Http:: / curl_exec call from this point on uses the updated CA bundle to validate the chain.

laravel curl error 60 — CA bundle path wiring from cacert.pem through php.ini to Guzzle

Fix 2 — Per-request 'verify' => false (local only)

When you genuinely need to ignore certificate verification — hitting a local dev server with a self-signed cert, reproducing a support issue — scope the bypass to the specific call:

use Illuminate\Support\Facades\Http;

$res = Http::withOptions(['verify' => false])
    ->get('https://example.com/someapi');

withOptions(['verify' => false]) applies to one pending request. The next Http::... call in the same process starts fresh with verification re-enabled, so the hole closes the moment you stop passing the option explicitly.

Never point 'verify' at false in production code. Disabling verification means a man-in-the-middle on the outbound path — compromised Wi-Fi, misconfigured load balancer, malicious DNS — can intercept and modify the response, and Laravel can’t tell. The CA-bundle fix in the section above is a one-time configuration change that costs nothing at runtime.

What not to do — edit vendor/guzzlehttp/

The old answer to this problem (and the one you’ll still find on forum threads) is to edit vendor/guzzlehttp/guzzle/src/Client.php and set 'verify' => false in the $defaults array. Three reasons to skip that:

  • composer update overwrites your change the moment Guzzle gets a patch release.
  • The change is invisible — nobody reading your codebase sees it, so “why are outbound calls insecure?” becomes a mystery bug.
  • It disables verification for every Guzzle call in the app, not just the one that’s failing.

Use the CA-bundle fix for anything that ships; use withOptions(['verify' => false]) scoped to the specific call for anything else.

If it’s “certificate has expired”

The CA-bundle fix assumes the remote cert is actually valid. If the error specifically says certificate has expired, check the remote cert first:

openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null \
    | openssl x509 -noout -dates

The notAfter line is the expiry. If it’s in the past, the remote server’s cert is genuinely expired — nothing you change on your server will fix that; the other side has to renew. Also double-check the server clock with timedatectl; a clock skew of more than a few minutes also triggers this error for perfectly valid certs.

Frequently asked questions

What’s the real cause of laravel curl error 60?

Your PHP install can’t validate the remote server’s SSL certificate — either because php.ini‘s curl.cainfo / openssl.cafile is unset (common on Windows and some minimal Linux images), the bundled CA file is out of date, or the remote cert is genuinely expired. It’s a PHP-level trust problem, not a Laravel one; Guzzle just surfaces whatever OpenSSL and libcurl report.

Should I set 'verify' => false in production?

No. Disabling verification turns off the single defense against man-in-the-middle attacks on your outbound API calls. It’s fine for debugging against a local server with a self-signed cert, or during a one-off support call when you know the endpoint is safe — never leave it in production code. The CA bundle fix below is a one-time setup that costs nothing at runtime.

Where do I download the CA bundle from?

curl.se/docs/caextract.html — the same Mozilla-derived bundle the curl project publishes, updated a few times a year. Save it somewhere stable on the server (for example /etc/ssl/certs/cacert.pem on Linux or C:\php\extras\ssl\cacert.pem on Windows), then point php.ini at it.

Does Http::withOptions(['verify' => false]) disable verification globally?

No — withOptions() applies to the specific pending request only. Each new Http::... call starts fresh with verification enabled. That makes it a safer escape hatch than editing vendor/guzzlehttp/guzzle/src/Client.php, because the scope is explicit at every call site.

The cert expired message says ‘certificate has expired’ — what then?

That’s either the remote server’s cert (check with openssl s_client -connect host:443 and look at notAfter), or your system clock is wrong, or the CA bundle is old enough to be missing a newer intermediate. Fix in that order: ask the remote-server operator if their cert is current, run timedatectl or check NTP, then update the CA bundle if the other two check out.

Related guides

  • Fix 403 Forbidden on Laravel Shared Hosting — another post-deploy problem on shared hosting.
  • How to Exclude .well-known from Redirection for Let’s Encrypt in Laravel — the inbound side of TLS on a Laravel box.
  • How to Install PHP 8.x on Ubuntu 22.04 — a clean PHP install where CA wiring usually works out of the box.
  • How to Install Laravel on Ubuntu — fresh Laravel 11 project setup.

References

Mozilla CA bundle extract: curl.se/docs/caextract.html. PHP curl.cainfo and openssl.cafile ini reference: php.net/manual/en/openssl.configuration.

TAGGED:configurationLaravelphpSecuritytroubleshooting

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
[mc4wp_form]
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article Laravel 403 forbidden on shared hosting — root htaccess rewrite into public folder Fix “403 Forbidden” on Laravel Shared Hosting
Next Article Laravel delete file from public folder — File::delete with public_path How to Delete Files from the Public Folder in Laravel
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow
Most Popular
Set vi as the default editor in Ubuntu — a terminal opening the vim editor
How to Set vi (Vim) as the Default Editor in Ubuntu
June 8, 2026
rsync says ALL DONE but files are missing — a terminal showing ALL DONE next to an empty folder
rsync Says “ALL DONE” but Files Are Missing: How to Verify
June 8, 2026
Migrate a website to a new server with rsync — files copying from an old server to a new one over SSH
How to Migrate a Website to a New Server With rsync
June 8, 2026
Bun runtime — faster JS toolkit replacing npm in Laravel projects
How to Install Bun Runtime on Ubuntu (And Use It in a Laravel Project)
May 24, 2026
Tailscale mesh — peer-to-peer connections between devices, coordination server
How to Install Tailscale on Ubuntu (Zero-Config Mesh VPN for Self-Hosters)
May 24, 2026

You Might Also Like

Extract a .tar.gz archive in PHP with PharData
Web Development

How to Extract a .tar.gz Archive in PHP

5 Min Read
Securely hash passwords in PHP with password_hash
Web Development

Securely Hash Passwords in PHP (password_hash, Argon2id)

6 Min Read
Remove all non-numeric characters from a PHP string
Web Development

How to Remove All Non-Numeric Characters from a String in PHP

4 Min Read
Check if Laravel scheduler is running (cron + php artisan schedule:run)
Web Development

How to Check if Laravel Scheduler Is Running (Cron + Logs)

6 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Tools

  • Age Calculator
  • Word Counter
  • Image Upscaler
  • Password Generator
  • QR Code Generator
  • See all tools→

Pranks

  • Fake Blue Screen Prank
  • Hacker Typer
  • Fake iMessage Generator
  • Windows XP Crash Prank
  • Windows 11 Update Prank
  • See all prank screens →

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service
  • Sitemap
© 2024–2026 How7o. All rights reserved.
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?