Certificate chains confuse almost everyone when they first encounter them. Not because they’re that complex in principle, but because the trust model isn’t obvious, and the problems that stem from incomplete chains show up in weird, inconsistent ways across different clients.
I’ve spent hours debugging “certificate not trusted” errors that turned out to have nothing to do with the certificate itself — just a missing intermediate. This is what I wish someone had explained to me before those debugging sessions.
Why Certificates Form a Chain
A browser trusts your website’s certificate not because it knows your domain, but because it trusts the organization that vouched for your domain. And it trusts that organization because a higher-level organization vouched for them. This chain of trust terminates at a Root CA whose certificate is pre-installed in the browser or operating system.
The chain looks like this:
Root CA (trusted by browsers/OS)
└── Intermediate CA (signed by Root CA)
└── Your Domain Certificate (signed by Intermediate CA)
When a browser connects to your site, it receives your domain certificate. It needs to verify the signature on your cert was made by a CA it trusts. But it usually doesn’t receive the Intermediate CA cert directly — your server needs to send it. If the intermediate is missing, the browser tries to look it up, sometimes succeeds (from cache), sometimes fails.
This is why a chain works in some browsers and fails in others: a browser that previously visited a site using the same intermediate CA has it cached. A fresh browser on a fresh machine doesn’t.
Root Certificates
Root CA certificates are self-signed — the CA signed its own certificate. This is the top of the chain. There’s no one above them to verify their signature; trust comes from being pre-installed in browsers and operating systems.
Root CA private keys are kept in extreme physical security, sometimes in Hardware Security Modules (HSMs) in vaults, only brought online for very specific operations. The reason is obvious: if the root CA private key is compromised, every certificate that chains up to it is compromised.
Root CAs don’t typically sign domain certificates directly — they create Intermediate CAs to do that. This way, if an Intermediate CA is compromised, they can revoke it without invalidating every certificate ever issued.
Intermediate Certificates
Most certificates you buy or issue come from an Intermediate CA, not directly from a Root CA. Your domain certificate’s “issuer” field names an Intermediate CA, and that Intermediate CA’s certificate is signed by the Root (or by another Intermediate, creating multi-level chains).
Intermediate certificates need to be served by your web server as part of the chain. If you only serve your domain certificate, clients must download the Intermediate cert themselves from the URL in the cert’s Authority Information Access (AIA) field.
This download usually works but:
- It adds latency (an extra HTTP request during the TLS handshake)
- It fails entirely in networks that block outbound HTTP
- It fails on clients that don’t implement AIA chasing (some embedded systems, some older Android versions)
So: always include the full chain on your server.
Building the Certificate Chain
You’ll typically receive these files from your CA:
- Your domain certificate
- One or more intermediate certificates
- Possibly a root certificate
For Nginx, combine them into a single file in order: domain cert first, then intermediates from “closest to your cert” up to “closest to root”:
cat domain.crt intermediate.crt > fullchain.pem
Do you need to include the root cert? Usually no. Browsers have root certs pre-installed. Including the root in your chain adds a few bytes to the TLS handshake but doesn’t change browser behavior. Some strict TLS implementations object to seeing the root in the chain. I leave the root out unless a client specifically requires it.
For Apache, separate files are used:
SSLCertificateFile /etc/ssl/domain.crt
SSLCertificateChainFile /etc/ssl/ca-bundle.crt
The ca-bundle.crt contains the intermediate(s).
Verifying Your Chain is Correct
Check the chain with OpenSSL:
openssl verify -CAfile ca-bundle.crt domain.crt
If the chain is complete and valid, you’ll see: domain.crt: OK
Check what’s actually in a chain file:
openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout
This lists all certificates in the bundle with their subject and issuer fields. You can trace the chain: each certificate’s issuer should match the next certificate’s subject.
Check the chain as served by your running server:
openssl s_client -connect example.com:443 -servername example.com -showcerts
The -showcerts flag shows every certificate in the chain as sent by the server. Count them: you should see your domain cert (cert 0) and at least one intermediate (cert 1). If you only see cert 0, the chain is incomplete.
Chain Completeness vs. Chain Order
Both matter. An incomplete chain (missing intermediates) causes trust failures. An incorrectly ordered chain can cause confusion or errors in strict implementations, even if all the pieces are present.
The correct order is always: most-specific to most-general.
1. Domain certificate (your site's cert)
2. Intermediate CA that signed your domain cert
3. Higher intermediate (if any)
4. Root CA (optional)
I’ve occasionally received chain files from CAs with the order reversed. It works in most cases because browsers and OpenSSL will sort it out, but it’s sloppy and occasionally breaks things.
Cross-Signed Certificates and the DST Root CA X3 Expiry
In 2021, Let’s Encrypt’s chain became a real-world lesson in how certificate chains work. Their root certificate (ISRG Root X1) had been cross-signed by DST Root CA X3 (an older root from IdenTrust). When DST Root CA X3 expired in September 2021, Android 7 and older, and some OpenSSL 1.0.x systems, stopped trusting Let’s Encrypt certificates.
The reason was nuanced: those clients prioritized the cross-signed path (through the expired DST Root CA X3) over the direct path (through ISRG Root X1, which was valid). The fix was for servers to serve a shorter chain that didn’t include the cross-signed certificate.
This is a real example of why understanding chains matters — a problem in a certificate your server didn’t even issue caused client failures.
OCSP and CRL: How Revocation Works in the Chain
Each certificate in the chain can be revoked. Your domain cert could be revoked if your private key is compromised. An Intermediate CA cert could be revoked if the CA is compromised (this is rare but has happened).
Revocation is checked via:
- OCSP (Online Certificate Status Protocol): Client makes an HTTP request to the CA asking if a specific certificate is still valid. Faster and more modern.
- CRL (Certificate Revocation List): CA publishes a list of revoked certificate serial numbers. Client downloads and checks the list. Older method, the lists can be large.
With OCSP Stapling (described in the Nginx and Apache guides), your server periodically fetches the OCSP response for your own certificate and includes it in the TLS handshake. This proves in real-time that your certificate hasn’t been revoked, without requiring the client to make a separate OCSP request.
Debugging Chain Issues in Practice
The most common chain issue is missing intermediates. The symptom: site works in Chrome (which uses its certificate cache aggressively) but fails in Firefox, curl, or API clients.
Quick test with curl:
curl -v https://example.com 2>&1 | grep -E "SSL|certificate|chain"
Test with a strict TLS check (no cached intermediates):
openssl s_client -connect example.com:443 -servername example.com 2>&1 | grep -E "Verify|depth"
Online tools like CrtMgr SSL Tools will also show chain completeness and flag any ordering issues.
Understanding the chain model makes most SSL troubleshooting much more straightforward. When you see an “untrusted” error, you’re not debugging your certificate — you’re debugging the path from your cert to a root the client trusts. Once you can visualize that path, the solution is usually obvious. For a step-by-step approach to diagnosing specific SSL errors, see our guide on troubleshooting SSL certificate errors