cURL Error 60 – DST Root CA X3 Expiry Breaks HTTPS on Ubuntu 14
On Ubuntu 14 (end-of-life) servers, all HTTPS requests to Let's Encrypt-secured sites fail with cURL error 60 ('SSL certificate problem: certificate has expired') because the DST Root CA X3 root certificate expired on 30 September 2021 and remains trusted in the local CA store. The remote certificates are valid; the fault lies entirely in the outdated local trust store. The fix is to deselect mozilla/DST_Root_CA_X3.crt via dpkg-reconfigure ca-certificates, which removes the expired root from the trusted set.
Indicators
- curl: (60) SSL certificate problem: certificate has expired on requests to Let's Encrypt-secured sites
- All HTTPS connections to Let's Encrypt sites fail simultaneously with no change to remote certificates
- openssl s_client confirms the remote certificate chain is valid and unexpired
- Issue is isolated to Ubuntu 14 hosts; other OS versions are unaffected
- Error appears suddenly with no modifications made to the target servers or their certificates
- DST_Root_CA_X3.pem or mozilla/DST_Root_CA_X3.crt present in /etc/ssl/certs with expiry of 30 Sep 2021
- curl or wget returns 'unable to get local issuer certificate' (missing intermediate CA in chain)
- Application logs show TLS handshake failure on outbound HTTPS calls
- Service-to-service calls begin failing simultaneously at a calendar date matching certificate expiry
- Monitoring alerts fire on HTTPS endpoint health checks returning non-2xx or connection refused
Likely causes
- DST Root CA X3 root certificate expired on 30 September 2021 and remains in the Ubuntu 14 local CA trust store
- Ubuntu 14.04 reached end-of-life and no longer receives ca-certificates package updates that would remove expired roots
- Let's Encrypt certificate chains include a cross-signature from DST Root CA X3; older OpenSSL versions prefer the expired cross-signed path over the valid ISRG Root X1 path
- No automated CA trust store maintenance or monitoring in place for EOL hosts
- Intermediate or root CA certificate missing from server's certificate chain or client's trust store
- Certificate CN or Subject Alternative Names (SANs) do not match the hostname being accessed
- Self-signed certificate used without being imported into client trust stores
- Certificate revoked by issuing CA and CRL/OCSP check fails
- System clock skew causes a valid certificate to appear expired or not yet valid
- Wrong (old) certificate still bound to the service listener after renewal
Diagnostic steps
-
Reproduce the error: run 'curl -v https://website.com' and confirm error 60 with the message 'SSL certificate problem: certificate has expired'.Confirms the error is reproducible and captures the exact error string for triage.
-
Verify the remote certificate chain is valid: run 'echo -n | openssl s_client -showcerts -connect website.com:443 -servername website.com' and confirm the server's certificate and intermediates are within their validity period.Determines whether the fault is in the remote certificate or the local trust store.
-
Locate DST Root CA X3 in the local trust store: check for '/etc/ssl/certs/DST_Root_CA_X3.pem' or list entries with 'ls /etc/ssl/certs/ | grep -i DST'.Confirms the expired root certificate is present in the local CA store.
-
Confirm the expiry date of the local DST Root CA X3 certificate: run 'openssl x509 -in /etc/ssl/certs/DST_Root_CA_X3.pem -noout -dates'. Expect 'notAfter=Sep 30 14:01:15 2021 GMT', confirming this root is the cause.Verifies the expired root is the specific certificate causing validation failure.
-
Cross-check the ca-certificates configuration file to confirm DST_Root_CA_X3.crt is marked as trusted: run 'grep -i DST /etc/ca-certificates.conf'.Confirms the expired root is actively trusted in the ca-certificates configuration.
-
Check system clock on client and server: run 'date; timedatectl' on Linux and compare to a trusted NTP source.Rules out clock skew as a false cause of certificate validity window failures.
-
Verify which certificate is actually bound to the service listener: on Linux inspect nginx/apache config for ssl_certificate or SSLCertificateFile directives; on Windows run 'netsh http show sslcert'.Confirms the renewed certificate has been deployed and bound, not merely uploaded.
-
Test trust chain from the client's perspective: run 'curl -v --cacert /path/to/ca-bundle.crt https://<host>' to isolate whether the fault is server-side (bad cert) or client-side (missing CA in trust store).Distinguishes a server certificate problem from a client trust store problem.
Resolution path
- Run: sudo dpkg-reconfigure ca-certificates
- At the first prompt 'Trust new certificates from certificate authorities?' select 'yes' and press Enter.
- On the certificate selection list, use the down arrow key to navigate to 'mozilla/DST_Root_CA_X3.crt'.
- Press the space bar to deselect it, changing [*] to [ ].
- Press Enter/Tab to select OK and apply the changes. The update-ca-certificates script will run automatically and remove the expired root.
- Verify the fix: run 'curl https://website.com' and confirm the request succeeds with no SSL error.
- Optionally confirm the certificate is no longer in the active bundle: run 'grep -r DST_Root_CA_X3 /etc/ssl/certs/' — the symlink should be absent.
- If intermediate CA is missing from the chain: obtain the full intermediate and root CA certificates from the issuing CA, append them to the server certificate file as a PEM bundle, and reload the service.
- If hostname mismatch: reissue the certificate with the correct CN or add the missing hostname to the SANs list, then redeploy.
- If clock skew: synchronise system time ('timedatectl set-ntp true' on Linux; 'w32tm /resync' on Windows) and retry — no certificate change required.
- If wrong certificate is bound (Windows IIS): navigate to Site > Bindings > Edit HTTPS binding in IIS Manager and select the correct certificate, then apply.
Prevention
- Upgrade Ubuntu 14.04 hosts to a supported LTS release (20.04 or later) that receives ongoing security and CA certificate updates.
- Keep the ca-certificates package updated on all active servers: 'sudo apt-get update && sudo apt-get install --only-upgrade ca-certificates'.
- Monitor CA expiration announcements from Let's Encrypt (letsencrypt.org/docs) and the Mozilla CA Certificate Program.
- Periodically audit local CA trust stores on all servers for expired root certificates: 'for f in /etc/ssl/certs/*.pem; do openssl x509 -in $f -noout -dates 2>/dev/null | grep notAfter; done'.
- Set up automated alerting for cURL/SSL errors in application and system logs to detect trust store issues early.
- Include EOL OS status in the infrastructure asset register and track supported-until dates to prioritise upgrades before CA update cessation.
- Implement automated certificate renewal (certbot with cron/systemd timer or ACME client integrated with load balancer) with alerts at 30, 14, and 7 days before expiry.
- Monitor certificate expiry for all externally and internally facing endpoints using Prometheus blackbox_exporter (probe_ssl_earliest_cert_expiry metric) or a dedicated certificate management platform.
- Always include all applicable hostnames as Subject Alternative Names (SANs) at issuance time to prevent hostname mismatch failures after DNS changes.
- Store private keys and certificates in a secrets manager (e.g., HashiCorp Vault, AWS ACM) with rotation policies rather than on-disk files managed manually.
Tools
- curl
- openssl
- openssl s_client
- dpkg-reconfigure
- certbot / acme.sh (automated certificate renewal via ACME protocol)
- certlm.msc / certmgr.msc (Windows certificate store management)
- netsh http show sslcert (Windows — show certificate-to-port bindings)
- timedatectl / w32tm (system clock synchronisation)
- Test-NetConnection (PowerShell — basic TCP/TLS connectivity test)