SSL, TLS, security headers
Fix incomplete SSL certificate chain and intermediate errors
Your server sends only the leaf certificate, missing intermediates. Browsers may cache them, but mobile clients and curl fail with 'unable to get local issuer certificate'.
What's happening
An incomplete SSL chain means the server sends only the leaf (end-entity) certificate during the TLS handshake without including the intermediate certificate that links the leaf to a trusted root. Path validation requires every certificate from leaf to root, and clients without a cached intermediate cannot complete validation.
Desktop browsers often hide the problem because they cache previously seen intermediates or download them via the Authority Information Access (AIA) extension. Mobile Safari, older Android WebView, and curl do not — they fail with 'unable to get local issuer certificate' or NET::ERR_CERT_AUTHORITY_INVALID.
The most common root cause is shipping cert.pem instead of fullchain.pem in nginx config, or forgetting to concatenate the intermediate when uploading a certificate to a load balancer. The fix is to install the full chain — the leaf followed by the intermediate(s), in order — on the server.
Why it matters
Mobile traffic — typically 50%+ of e-commerce visits — sees connection failures or browser warnings while desktop visitors load the site fine. The intermittent nature of the bug makes it especially hard to diagnose from a developer laptop.
API consumers using curl, Python's requests, Go's net/http, or any client without an aggressive intermediate cache will fail to connect. Webhook deliveries from Stripe, GitHub, and Slack will time out and dead-letter.
SSL Labs grades a server with an incomplete chain at most a B and includes a warning in the public report. Search engines that use stricter validation paths than Chrome may treat the URL as a security issue.
Common causes
- Nginx is configured with
ssl_certificate cert.peminstead ofssl_certificate fullchain.pem. - Apache uses
SSLCertificateFilefor the leaf only and omitsSSLCertificateChainFile(pre-2.4.8) or fails to bundle in 2.4.8+. - A certificate uploaded to AWS ELB, Azure App Service, or GCP load balancer was the leaf only without the issuer chain pasted in.
- A custom build script concatenates files in the wrong order — root must be last and is optional, leaf must be first.
- The CA changed its intermediate after issuance and the server still serves the old one.
Detect this on your site
Run a quick scan with the SSL Checker. The tool surfaces this exact issue with the records and context needed to apply the fix below.
Open SSL CheckerHow to fix it
- 1
Inspect the chain on the wire
Run
openssl s_client -servername example.com -connect example.com:443 -showcerts </dev/null. Count the BEGIN CERTIFICATE blocks — there must be at least two for a leaf-plus-intermediate chain. If you only see one, the server is misconfigured. - 2
Identify the correct intermediate
Look at the leaf's Issuer field and download the matching intermediate from your CA's documentation. Let's Encrypt publishes them at letsencrypt.org/certificates/. DigiCert, Sectigo, and GoDaddy all publish chains in their portals. Save it as
intermediate.pem. - 3
Build a fullchain bundle
Concatenate leaf followed by intermediate:
cat cert.pem intermediate.pem > fullchain.pem. Order matters — the leaf must be first. Some CAs ship a 'chain.pem' that contains only the intermediate; never serve that alone. - 4
Update nginx or Apache
In nginx, change the directive to
ssl_certificate /path/to/fullchain.pem;. In Apache 2.4.8+, the same SSLCertificateFile directive accepts a concatenated bundle. For older Apache, setSSLCertificateChainFile /path/to/intermediate.pem. - 5
Reload and re-verify
Run
sudo nginx -t && sudo systemctl reload nginx. Then run the openssl s_client command again and confirm the chain depth is now 2 or 3. Verify on a fresh device that has never visited the site so there is no cached intermediate. - 6
Test from a chain-strict client
Run
curl -v https://example.comwith no flags. If it succeeds, the chain is correct. Also run the SSL Checker at /ssl, which simulates strict clients and grades the chain.
Example
# Build a correct fullchain from leaf + intermediate
cat /etc/ssl/certs/example.com.crt \
/etc/ssl/certs/lets-encrypt-r3.pem \
> /etc/ssl/certs/example.com-fullchain.pem
# Verify chain depth
openssl s_client -servername example.com -connect example.com:443 -showcerts </dev/null 2>/dev/null \
| grep -c 'BEGIN CERTIFICATE'Concatenate leaf and intermediate, then count cert blocks served
Frequently asked
Chrome uses AIA fetching to download missing intermediates from the URL embedded in the leaf certificate. Firefox does not enable AIA fetching by default. The site looks fine in Chrome and broken in Firefox until you ship the full chain.
No. The root is already in every client's trust store; including it adds bytes to every handshake without improving validation. Ship leaf and intermediate(s) only.
Related fixes
SSL, TLS, security headers
Fix expired SSL certificate and restore HTTPS access
SSL, TLS, security headers
Replace self-signed SSL certificate with a trusted CA cert
SSL, TLS, security headers
Enable OCSP stapling to speed up TLS handshakes and improve privacy
SSL, TLS, security headers
Fix SSL certificate hostname mismatch errors in browsers