VPS Tutorials
Fix curl 60 SSL certificate problem on a VPS (2026): CA, certificate chain and hostname checks
A browser works but curl on your VPS fails certificate validation? Distinguish untrusted CAs, incomplete server chains, hostname mismatches and CA-file errors, repair the actual runtime and retain TLS verification.

Does curl on the VPS report curl: (60) SSL certificate problem for an HTTPS endpoint that works in your browser? Do not add -k to every script. The client failed to validate the server certificate. The cause may be the client trust store, server chain, requested hostname or system clock.
This guide checks the actual connection, inspects certificates and identifies which side needs repair. It applies to API calls, installation scripts and automation. TLS validation fails before normal HTTP handling; distinguish it from API responses such as 401, 403 and 404.
Run checks on the same VPS, container and user that failed, replacing the domain with your real target:
curl --version
date -u
curl -v --connect-timeout 10 --max-time 30 https://api.example.com/
Inspect the TLS backend, connection address, certificate messages and proxy use. Builds may use different CA stores. A successful host command does not prove the container or application SDK works. Remove Authorization, Cookie, proxy credentials and sensitive URLs before sharing -v output.
| Message or symptom | First checks | Common repair |
|---|---|---|
unable to get local issuer certificate | CA source and server intermediate certificates | Complete the server chain or configure the correct client CA |
certificate has expired | Certificate validity and current time | Install the correct certificate or fix clock drift |
| Hostname mismatch | URL, DNS, certificate SAN and SNI | Use the correct hostname and site certificate |
| Self-signed certificate or internal CA | A clearly established trust source | Configure a verified CA for this request |
| Unreadable or invalid CA file | Path, permissions and format | Repair the local file; this may be error 77 |
curl's certificate verification guidance says validation includes the trust chain and the URL hostname. Browser and curl trust stores, caches and chain-completion behaviour can differ, so browser success does not rule out a server misconfiguration.
With OpenSSL available, inspect the handshake and server certificates:
openssl s_client -connect api.example.com:443 \
-servername api.example.com -showcerts \
-verify_hostname api.example.com -verify_return_error </dev/null
-servername sends SNI; -verify_hostname checks the hostname. They are separate operations. -showcerts lists supplied certificates, not proof of successful chain validation. The s_client documentation explains that this diagnostic tool may continue after verification errors by default; -verify_return_error here aborts the handshake on error.
Inspect the leaf certificate's names, issuer and validity, plus necessary intermediates. Public sites normally send the leaf and intermediate certificates; the root generally comes from the client trust store. Two certificates or a filename of fullchain.pem does not establish correct configuration.
If your Nginx is responsible, configure the full chain as the issuer instructs, check syntax, reload and repeat the handshake. For issuance or renewal failures, see Let's Encrypt renewal troubleshooting.
If a certificate is issued to api.example.com but you access https://服务器IP/, verification may fail unless the IP is covered by the corresponding SAN. Changing only the HTTP Host header does not change the hostname verified from the URL.
To connect directly to a chosen server for diagnosis, keep the domain and override resolution for that connection:
curl --resolve api.example.com:443:203.0.113.10 \
https://api.example.com/
Replace the documentation example IP with a confirmed target. --resolve does not disable verification; the URL hostname still governs TLS. If the origin certificate is trusted only by a particular proxy, direct clients may still fail. Check the deployment's trust design using Cloudflare 525 / 526 and origin certificates.
If several otherwise normal public HTTPS sites fail and names and time are correct, check missing or old CA packages in the system or base image and custom paths overriding them.
On apt-based Debian / Ubuntu, update or repair the distribution package according to your maintenance schedule:
sudo apt update
sudo apt install --reinstall ca-certificates
sudo update-ca-certificates
The update-ca-certificates manual describes system trust-store updates. This is not universal across operating systems and TLS backends. Containers need their own package; include the repair in the image build when rebuilding.
Also check explicit --cacert, CURL_CA_BUNDLE, SSL_CERT_FILE or SSL_CERT_DIR settings. Understand which application they serve before fixing paths or contents; do not casually clear production configuration. Python, Java and Node.js applications may not reuse curl's CA configuration.
For an internal service, obtain and verify its CA certificate through a trusted management channel. Do not blindly trust a certificate downloaded from the failing connection. Specify it for an individual call:
curl --cacert /path/to/verified-root-ca.pem https://internal.example.com/
Chain and hostname verification remain enabled; this does not validate expired certificates or wrong names. Supply an appropriate PEM certificate, not a private key, webpage or saved error response. The actual runtime user must be able to read the path. Behaviour of --cacert depends on the TLS backend and curl option documentation.
Adding an internal CA to the machine-wide trust store expands trust. Follow the organization's certificate process. If only one application needs it, consider its supported separate CA configuration first and document rotation.
-k / --insecure skips verification. Success only shows that the connection can proceed past that step. It does not distinguish a missing intermediate, untrusted CA or wrong site. Do not keep it as a fix in production API calls, installers or scheduled jobs.
Finally retest the real command without -k in the actual runtime. Confirm certificate validation, then the expected HTTP status and application response. A later 401 or 404 needs authentication or routing diagnosis, not further CA changes.
The source article reports 6 local checks on macOS with curl 8.7.1 (SecureTransport) and OpenSSL 3.6.0: missing intermediates, untrusted CA and incorrect hostname each caused curl 60; a full chain with the specified CA returned 200; a missing CA file caused 77; OpenSSL chain and hostname verification passed. These checks used temporary certificates and loopback services without changing system trust. They did not cover public certificate renewal, Ubuntu package installation, proxy chains, container images or real application SDKs.