When your browser connects to an HTTPS site, it doesn’t just trust the certificate blindly. It verifies a chain of trust — a linked series of certificates leading from your site’s certificate up to a pre-trusted root Certificate Authority (CA).
The three levels
┌─────────────────────────────────┐
│ ROOT CA │ Pre-installed in browsers/OS
│ (ISRG Root X1 for LE) │ Self-signed, long validity (20+ years)
└───────────────┬─────────────────┘
│ signs
▼
┌─────────────────────────────────┐
│ INTERMEDIATE CA │ Signed by the root
│ (Let's Encrypt R3/R10) │ Medium validity (5-10 years)
└───────────────┬─────────────────┘
│ signs
▼
┌─────────────────────────────────┐
│ YOUR CERTIFICATE │ Signed by the intermediate
│ (example.com) │ Short validity (90 days for LE)
└─────────────────────────────────┘
Root CA — Trusted by browsers and operating systems. Stored in the device’s certificate store. Self-signed (no one signs for the root — it IS the trust anchor). Root keys are kept offline in hardware security modules.
Intermediate CA — Signed by the root. Actually issues end-entity certificates. If an intermediate is compromised, only it needs to be revoked — the root stays safe.
End-entity certificate — Your certificate. Signed by the intermediate. This is what your server sends to browsers.
How verification works
When your browser receives a certificate:
- Read your certificate — extract the issuer name
- Find the intermediate — either from the server’s response or the browser’s cache
- Verify intermediate signature — check it’s signed by a trusted root
- Verify your cert’s signature — check it’s signed by the intermediate
- Check validity dates — neither certificate is expired
- Check domain match — the certificate’s SAN/CN matches the URL
- Check revocation — certificate hasn’t been revoked (OCSP/CRL)
If any step fails → browser shows a security warning.
Why the intermediate matters
The most common SSL error is a missing intermediate certificate. If your server sends only your certificate without the intermediate, browsers can’t build the trust chain.
Nginx expects fullchain.pem (your cert + intermediate combined):
ssl_certificate /etc/ssl/fullchain.pem; # cert + intermediate
Apache uses separate files:
SSLCertificateFile /etc/ssl/cert.pem # your cert
SSLCertificateChainFile /etc/ssl/chain.pem # intermediate
GetHTTPS provides both fullchain.pem and separate cert.pem + chain.pem files, so you have the right format for any server.
Let’s Encrypt’s chain
Let’s Encrypt’s current chain:
ISRG Root X1 (root, in all trust stores)
└── Let's Encrypt R10 (intermediate, signs your cert)
└── yourdomain.com (your certificate)
There’s also a cross-signed path through IdenTrust’s DST Root CA X3 for compatibility with older devices, but this is no longer needed for most use cases.
Frequently asked questions
How do I fix “certificate not trusted” errors?
Almost always: you’re missing the intermediate certificate. Use fullchain.pem (Nginx) or add SSLCertificateChainFile chain.pem (Apache). Test with:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com
Look for “verify return:1” (good) vs “verify return:0” (chain problem).
Can I see the chain in my browser?
Yes. Click the padlock → “Certificate” (or “Connection is secure” → “Certificate is valid”). You’ll see the chain: your cert → intermediate → root.
What happens if a root CA is compromised?
The root is removed from trust stores via browser/OS updates. All certificates issued under that root become untrusted. This is extremely rare — root keys are stored in offline hardware security modules with physical access controls.
Why does Let’s Encrypt use an intermediate certificate instead of signing directly with the root?
Security isolation. If the intermediate key is compromised, only it needs to be revoked — the root stays safe. The root key is kept offline and only used to sign intermediates. This is standard practice for all major Certificate Authorities.
Do I need to install the root certificate on my server?
No. Root certificates are pre-installed in browsers and operating systems. Your server only needs to send your certificate + the intermediate. The browser already has the root and uses it to verify the chain.
Debugging chain issues
The most common SSL error in production is an incomplete certificate chain. Here’s a systematic way to diagnose:
Step 1: Check the chain your server sends
echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null
Look at the output:
Certificate chain
0 s:CN = example.com
i:C = US, O = Let's Encrypt, CN = R10
1 s:C = US, O = Let's Encrypt, CN = R10
i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
---
Verify return code: 0 (ok)
- Depth 0 = your certificate
- Depth 1 = intermediate
- “Verify return code: 0 (ok)” = chain is complete
If you only see depth 0 (no depth 1), the intermediate is missing.
Step 2: Fix the chain
Nginx: Use fullchain.pem (cert + intermediate combined):
ssl_certificate /etc/ssl/fullchain.pem; # NOT cert.pem
Apache: Add the intermediate explicitly:
SSLCertificateChainFile /etc/ssl/chain.pem
If you lost chain.pem: Download Let’s Encrypt’s intermediate from letsencrypt.org/certificates or re-issue your certificate with GetHTTPS.
Step 3: Verify the fix
echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | grep "Verify return code"
# Must say: Verify return code: 0 (ok)