Skip to content
← All articles

Incomplete SSL Certificate Chain: How to Diagnose and Fix It

Incomplete SSL Certificate Chain: How to Diagnose and Fix It

An incomplete certificate chain is when the server returns only its leaf cert without intermediates. Desktop browsers can often fetch missing intermediates from cache, but mobile clients, older libraries, curl, Java apps, and API документацию clients cannot — and fail with “unable to get local issuer certificate”. This guide covers diagnosis and assembling a correct fullchain.

Why the chain matters

The trust chain is the hierarchy from your leaf cert up to a root CA the client trusts:

Root CA (in the client's trust store)
  └─ Intermediate CA 1
      └─ Intermediate CA 2 (optional)
          └─ Leaf (your example.com cert)

The client must build a path from your leaf to a trusted root. Missing intermediates — no path. Don't send the root in the chain (not required; wastes bytes).

Symptoms of a broken chain

Diagnosis

First check:

openssl s_client -connect example.com:443 -servername example.com -showcerts < /dev/null 2>/dev/null \
    | grep "^-\|^ *s:\|^ *i:"

Correct output has at least two s: / i: pairs:

s:CN=example.com
i:C=US, O=Let's Encrypt, CN=R3
s:C=US, O=Let's Encrypt, CN=R3
i:C=US, O=Internet Security Research Group, CN=ISRG Root X1

Only one block — chain is broken. Also try the enterno.io SSL Checker or SSL Labs — they'll flag chain issues.

Fix: assemble fullchain.pem

Let's Encrypt makes this trivial — use fullchain.pem, it already contains leaf + intermediate:

# Correct
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

# Wrong (leaf only)
ssl_certificate /etc/letsencrypt/live/example.com/cert.pem;

Commercial CAs ship an archive with multiple files: cert.crt, intermediate.crt, sometimes root.crt. Concatenate leaf and intermediate in the right order:

cat cert.crt intermediate.crt > fullchain.crt
# Your leaf first, intermediate second
# DO NOT include the root

With multiple intermediates, the order is: leaf → intermediate nearest to leaf → next intermediate → etc. Wrong order — clients still fail.

nginx and Apache config

nginx:

ssl_certificate     /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;

Apache:

SSLCertificateFile      /etc/apache2/certs/cert.crt
SSLCertificateKeyFile   /etc/apache2/certs/privkey.key
SSLCertificateChainFile /etc/apache2/certs/intermediate.crt
# Or (Apache 2.4.8+) leaf+intermediate in one file:
SSLCertificateFile      /etc/apache2/certs/fullchain.pem

After changes: nginx -t && systemctl reload nginx or apachectl configtest && systemctl reload apache2.

Where to get intermediates if you've lost them

  1. CA website: Let's Encrypt — letsencrypt.org/certificates, Sectigo, DigiCert — their own pages.
  2. AIA (Authority Information Access): the cert contains an URL to the intermediate:
    openssl x509 -in cert.crt -noout -text | grep "CA Issuers"
    # CA Issuers - URI:http://r3.i.lencr.org/
    curl http://r3.i.lencr.org/ | openssl x509 -inform DER -out intermediate.pem
  3. crt.sh: look up your cert on crt.sh and follow the issuer link.

Automation and prevention

Related issues

Frequently asked questions

Should the root CA be in fullchain.pem?

No. The client already has it in the trust store. Sending it just bloats the handshake.

What about cross-signed intermediates for old Android?

Use Let's Encrypt's “long chain” where the intermediate is signed by the old DST Root CA X3. Certbot defaults to the short ISRG Root X1 chain — for Android < 7.1.1 force --preferred-chain "ISRG Root X1".

Why does Chrome work but Python requests doesn't?

Chrome can fetch intermediates via AIA from its cache. Python requests uses a certifi bundle containing only roots. You need a full chain on the server.

Fastest way to test from mobile?

Use an online service that doesn't share your desktop cache. enterno.io SSL Checker validates from its own environment — equivalent to a “clean” client.

Conclusion

Incomplete chain is a silent issue: invisible on desktop, broken on mobile and API integrations. The fix: build a correct fullchain.pem once and add continuous chain monitoring. enterno.io SSL Checker validates the chain in 15 seconds, and Monitors repeats every 5 minutes 24/7. See also cert date errors and handshake failed.

Path validation — RFC 5280, §6. Let's Encrypt chains — letsencrypt.org/certificates. Test — SSL Labs.

Check your website right now

Check now →
More articles: SSL
SSL
How to Check SSL Certificate and Never Miss Expiration
12.04.2026 · 12 views
SSL
Weak Cipher Suites: How to Find and Disable Insecure TLS Ciphers
15.04.2026 · 6 views
SSL
Expired SSL Certificate: How to Fix NET::ERR_CERT_DATE_INVALID
15.04.2026 · 8 views
SSL
Free SSL via Let's Encrypt: Install certbot in 10 Minutes
15.04.2026 · 8 views