
Troubleshooting SSL Certificate Issues with cURL
Unraveling the Mystery of cURL Error 60: How a Missing Certificate Chain File Caused Headaches and the Simple Fix That Saved the Day
Identifying the Problem
I recently encountered an issue with a client’s website. Upon investigation, I discovered that the problem was related to cURL in a CodeIgniter 4 environment. The logs revealed the following error:

CRITICAL — 2025–03–20 12:09:34 → cURL error 60: SSL certificate problem: certificate has expired (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://xxx_org/graphql
After examining the situation, I confirmed that the SSL certificate had indeed expired. To resolve this, I generated a new SSL certificate and proceeded with the redeployment process.
Certificate Files Overview
The Certificate Authority (CA) provided the following set of files:
xxx_org.crt # Server certificate file issued by the Certificate Authority
xxx_org.csr # Certificate Signing Request file
xxx_org__rsa.key # Private key file
xxx_org__crt.pem # Intermediate certificate (chain) file
xxx_org.ca # Chain certificate file (additionally provided)Initial Configuration Attempt
I configured the Apache virtual host settings file (000-default.conf) as follows:
<VirtualHost *:443>
.....
SSLEngine on
SSLCertificateFile /etc/ssl/certs/xxx_org.crt
SSLCertificateKeyFile /etc/ssl/private/xxx_org__rsa.key
SSLCertificateChainFile /etc/ssl/certs/xxx_org__crt.pem
</VirtualHost>The Mixed Results
After implementing this configuration, browser-based HTTPS access worked perfectly fine. However, when attempting to use cURL, I encountered another error:
CRITICAL — 2025–03–20 10:01:26 → cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://xxx_org/graphql
Root Cause Analysis
This error indicated that the xxx_org__crt.pem file likely did not contain the complete intermediate certificate authority information or had other structural issues. When dealing with certificate authorities that have lower levels of trust, it's advisable to avoid using the .pem file and instead configure using the .ca file.
A properly formatted .pem file containing the intermediate CA certificate would typically work without issues. You can verify the contents of a .pem file by checking for multiple -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- blocks. Multiple blocks indicate that the file includes both the certificate and the chain. A single block suggests it's only a single certificate file.
Successful Resolution
The alternative configuration that resolved the issue was:
<VirtualHost *:443>
.....
SSLEngine on
SSLCertificateFile /etc/ssl/cert/xxx_org.crt
SSLCertificateKeyFile /etc/ssl/cert/xxx_org__rsa.key
SSLCertificateChainFile /etc/ssl/cert/xxx_org.ca
</VirtualHost>The xxx_org.ca file properly contained the intermediate certificate authority's certificate, which completed the certificate chain and allowed everything to function correctly.
Lessons Learned
This issue could have been avoided if the .ca file had been available from the beginning. Unfortunately, the client reported they didn't initially have access to the .ca file, which led to the problems when using only the .pem file. This highlights the importance of obtaining all necessary certificate components when implementing SSL.
This essay was originally published on Medium and migrated to KanApp Blog.


Comments
Join the conversation
Sign in to leave a comment.
Comment login is being configured.
No comments yet.