Fix SSL Certificate Chain Errors: Nginx, Apache & Troubleshooting Guide

TL;DR: Certificate chain issues happen when your server doesn't send the complete chain of certificates needed to verify trust. The fix is usually simple: concatenate your certificate with the intermediate certificate(s) from your CA. This guide covers how to diagnose the problem and fix it for Nginx, Apache, Let's Encrypt, and other servers.
Related: If you're dealing with expired certificates instead of chain issues, check out our SSL Certificate Expiration Guide.
Quick Symptoms Check
You likely have a certificate chain issue if:
- ✅ Site works in Chrome/Firefox
- ❌
curlfails with SSL errors - ❌ API clients can't connect
- ❌ Mobile apps show certificate warnings
- ❌ SSL Labs shows "Chain Incomplete"
If this sounds familiar, you're in the right place.
The Confusing Part About Chain Errors
Here's a scenario that frustrates every DevOps engineer at some point:
Your website works fine in Chrome. No warnings, green padlock, everything looks secure. But then:
- Your API clients start failing with SSL errors
curlrefuses to connect- Automated health checks report certificate problems
- Mobile apps on certain devices show trust errors
The certificate isn't expired. The domain matches. So what's going on?
The answer is almost always: incomplete certificate chain.
What is a Certificate Chain?
When a browser or client connects to your server over HTTPS, it needs to verify that your certificate can be trusted. This verification follows a chain of trust:
Root CA (Trusted by OS/Browser)
↓
Intermediate CA (Signed by Root)
↓
Your Certificate (Signed by Intermediate)
Why Intermediates Exist
Certificate Authorities don't sign end-entity certificates directly with their root certificate. Instead, they use intermediate certificates because:
- Security: If a root key is compromised, it's catastrophic. Keeping it offline and using intermediates limits exposure.
- Flexibility: CAs can issue different intermediates for different purposes or validity periods.
- Revocation: Revoking an intermediate is easier than revoking a root.
The Problem
Your server needs to send the complete chain (your certificate + intermediates) to clients. Root certificates are already trusted by operating systems and browsers, so you don't send those. But if you only send your certificate without the intermediates, clients can't verify the chain.
Common Certificate Chain Errors
| Error | Symptoms | Common Cause |
|---|---|---|
| Incomplete chain | Works in browser, fails in curl/API clients | Missing intermediate certificate |
| Wrong order | Nginx fails to start with key mismatch error | Certificates concatenated in wrong order |
| Expired intermediate | Intermittent failures, some clients work | Old intermediate not updated during renewal |
| Self-signed in chain | Trust errors everywhere | Development cert accidentally deployed |
| Mismatched certificates | TLS handshake failures | Wrong intermediate for your certificate |
Why It Works in Browsers But Fails Elsewhere
This is the most confusing part of chain issues. Your site loads fine in Chrome, but curl fails. Why?
AIA Fetching
Modern browsers implement Authority Information Access (AIA) fetching. When they encounter a certificate without the full chain, they look at the AIA extension in your certificate, download the missing intermediate, and complete the chain themselves.
Browser Caching
Browsers also cache intermediate certificates. If you've ever visited a site that properly served the intermediate, your browser remembers it. So even if another site doesn't serve it, the browser already has it cached.
Why You Can't Rely on This
Here's the problem:
curl,wget, and most HTTP libraries don't do AIA fetching- API clients and backend services don't do AIA fetching
- Some mobile browsers don't do AIA fetching
- Fresh browser installs might not have cached intermediates
- Automated monitoring tools will report failures
Bottom line: Your server must send the complete chain. Don't rely on browser workarounds.
How to Diagnose Chain Issues
Method 1: Online SSL Checker (Fastest)
Use our free SSL Certificate Checker to instantly see:
- Whether your certificate chain is complete
- Which intermediate certificates are being served
- Any chain validation errors
This is the quickest way to diagnose the problem without command-line tools.
Method 2: OpenSSL Command Line
For a detailed look at what your server is sending:
openssl s_client -connect yourdomain.com:443 -showcerts
Look for the certificate chain in the output. You should see multiple certificates:
Certificate chain
0 s:CN = yourdomain.com
i:CN = R3, O = Let's Encrypt
1 s:CN = R3, O = Let's Encrypt
i:CN = ISRG Root X1, O = Internet Security Research Group
If you only see certificate 0 (your cert), the chain is incomplete.
Method 3: SSL Labs Test
For comprehensive analysis, use SSL Labs Server Test. It provides:
- Detailed chain analysis
- Trust status across different platforms
- Overall security grade
- Specific recommendations
Look for "Chain issues" in the results. Common messages include:
- "Contains anchor" (you're sending the root, which is unnecessary but not harmful)
- "Incomplete" (missing intermediate)
- "Extra certs" (extra certificates that aren't part of the chain)
How to Fix Certificate Chain Issues
Fix: Missing Intermediate Certificate
This is the most common issue. You need to get the intermediate certificate(s) from your CA and configure your server to send them.
Where to get intermediate certificates:
- Your CA's documentation or downloads page
- The email/portal where you received your certificate
- What's My Chain Cert - paste your cert, get the full chain
Fix for Nginx
Nginx requires a single file containing your certificate followed by the intermediate(s):
# Concatenate your cert with the intermediate
cat your-certificate.crt intermediate.crt > combined.crt
Important: Your certificate must come first, then the intermediate(s).
Update your Nginx config:
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/nginx/ssl/combined.crt;
ssl_certificate_key /etc/nginx/ssl/your-private.key;
# ... rest of config
}
Reload Nginx:
sudo nginx -t && sudo systemctl reload nginx
Fix for Apache
Apache uses separate directives for the certificate and chain:
<VirtualHost *:443>
ServerName yourdomain.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/your-certificate.crt
SSLCertificateChainFile /etc/ssl/certs/intermediate.crt
SSLCertificateKeyFile /etc/ssl/private/your-private.key
# ... rest of config
</VirtualHost>
Restart Apache:
sudo apachectl configtest && sudo systemctl restart apache2
Fix for Let's Encrypt / Certbot
Certbot usually handles the chain automatically, but issues can occur if you're using the wrong file. Here's what Certbot generates:
ls /etc/letsencrypt/live/yourdomain.com/
# cert.pem - Your certificate only (INCOMPLETE!)
# chain.pem - Intermediate certificate(s) only
# fullchain.pem - Your cert + intermediates (USE THIS!)
# privkey.pem - Your private key
Common mistake: Using cert.pem instead of fullchain.pem.
Nginx with Let's Encrypt:
server {
listen 443 ssl;
server_name yourdomain.com;
# Use fullchain.pem, NOT cert.pem
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# ... rest of config
}
Apache with Let's Encrypt:
<VirtualHost *:443>
ServerName yourdomain.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
# ... rest of config
</VirtualHost>
If you're using Certbot's --nginx or --apache plugins, it should configure this correctly. If you're having chain issues with Let's Encrypt, double-check you're referencing fullchain.pem.
Fix: Wrong Certificate Order
If Nginx fails to start with an error like:
SSL_CTX_use_PrivateKey_file failed
(SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch)
You likely concatenated the certificates in the wrong order. The correct order is:
- Your server certificate (leaf)
- Intermediate certificate(s)
- (Never include the root)
Rebuild the combined file:
# Correct order: your cert first, then intermediate
cat your-certificate.crt intermediate.crt > combined.crt
# NOT this (wrong order):
# cat intermediate.crt your-certificate.crt > combined.crt
Fix: Expired Intermediate Certificate
If your intermediate has expired:
- Download the current intermediate from your CA
- Check the expiration:
openssl x509 -in intermediate.crt -noout -dates - Replace the old intermediate and rebuild your chain file
- Reload your web server
Fix: Multiple Intermediates
Some CAs use multiple intermediates (a chain of intermediates). In this case, concatenate them in order from your cert up to (but not including) the root:
cat your-cert.crt intermediate1.crt intermediate2.crt > combined.crt
The order should follow the chain: your cert → intermediate that signed your cert → intermediate that signed that intermediate → etc.
Verification After Fixing
After making changes, verify the fix:
Quick Test with curl
curl -v https://yourdomain.com 2>&1 | grep -A5 "Server certificate"
If curl connects without SSL errors, you're good.
Verify with OpenSSL
openssl s_client -connect yourdomain.com:443 -showcerts 2>/dev/null | grep -E "^( [0-9]|Certificate chain)"
You should see multiple certificates in the chain.
Re-run SSL Checker
Run our SSL Certificate Checker again to confirm the chain is now complete.
Prevention: Avoiding Chain Issues
1. Always Install the Full Chain
When you receive a certificate from your CA, they typically provide:
- Your certificate
- Intermediate certificate(s) or a "CA Bundle"
Always install both, even if things seem to work without it.
2. Automate Certificate Management
Tools like cert-manager (Kubernetes), AWS Certificate Manager, or Let's Encrypt's certbot handle chain management automatically. Less manual intervention means fewer mistakes.
3. Test After Every Renewal
Certificate renewals can introduce chain issues if:
- The CA changed their intermediate
- Automation only renewed the cert but not the chain file
- Manual steps were missed
Add SSL validation to your deployment pipeline or post-renewal hooks.
4. Monitor Your Certificates
Don't wait for users to report problems. Use monitoring to catch issues before they impact production.
CertWatch can monitor your certificates and alert you to chain validation failures, expiring certificates, and other issues before they cause outages.
Quick Reference Commands
Check certificate chain
openssl s_client -connect example.com:443 -showcerts
View certificate details
openssl x509 -in certificate.crt -text -noout
Verify certificate matches private key
# These should output the same hash
openssl x509 -noout -modulus -in certificate.crt | openssl md5
openssl rsa -noout -modulus -in private.key | openssl md5
Concatenate certificates for Nginx
cat your-cert.crt intermediate.crt > combined.crt
Test with curl (verbose SSL)
curl -vI https://example.com 2>&1 | grep -E "(SSL|certificate)"
Key Takeaways
- Chain issues are the most common SSL problem after expiration—and they're easy to miss because browsers work around them
- Always serve the complete chain: your certificate + intermediate(s)
- Order matters for Nginx: your cert first, then intermediate(s)
- Don't rely on browser behavior—test with curl, OpenSSL, or online checkers
- Automate and monitor to catch issues before they affect users
Need Help?
If you're still stuck with certificate chain issues or want to discuss SSL configuration, join our community:
Sources
Never Let a Certificate Expire Again
Monitor your SSL certificates with CertWatch. Get alerts before they expire, validate certificate chains, and keep your services running smoothly.