Validating Certificate Chains Across CDN and Origin

Problem Statement

When a CDN sits in front of your site there are two TLS connections, not one, and they fail independently. Visitors negotiate with the edge and validate the edge’s certificate; the edge negotiates separately with your origin and validates the origin’s. A migration can leave either one broken while the other is perfect — and the two failures look nothing alike. A broken edge certificate produces an immediate, visible interstitial for everyone. A broken origin certificate produces nothing at all until somebody enables strict origin verification, or until a cache entry expires and the edge has to re-fetch, at which point the site fails everywhere at once for reasons nobody can trace to a change made weeks earlier. This page sits under TLS & Certificate Cutover and covers checking both.

When to Use This Approach

  • A CDN, load balancer, or reverse proxy terminates TLS in front of your origin.
  • You are moving the origin, the edge provider, or both.
  • Non-browser clients — mobile apps, payment gateways, partner integrations — call your hostnames.
  • The origin currently uses a self-signed or internal certificate that “works” because verification is disabled.
  • You need evidence that the chain is complete rather than the impression that the site loads.

Step-by-Step Instructions

1. Check the Edge Certificate the Way a Strict Client Would

Browsers are the most forgiving client you have: they cache intermediates from other sites and can fetch a missing one on demand, so a chain that is incomplete on the wire still renders a padlock. Count what the server actually sends instead of trusting the padlock.

# Two or more certificates means leaf + intermediate(s); one means an incomplete chain
openssl s_client -connect www.example.com:443 -servername www.example.com \
  -showcerts </dev/null 2>/dev/null | grep -c 'BEGIN CERTIFICATE'

Where the count comes back as one, the fix is almost always a configuration pointing at the leaf-only certificate file rather than the full chain. Servers accept either without complaint and serve exactly what they are given, so the defect is invisible in the config and obvious on the wire. Repeat the count after every certificate deployment rather than only the first, because a renewal that writes to a different filename is a common way for a previously correct chain to regress.

2. Check the Origin Certificate Directly, Bypassing the Edge

The edge’s view of your origin is the one that matters for the second connection, and you cannot see it through the public hostname. Connect to the origin’s address with the real SNI, exactly as the edge does, and validate what comes back.

# Talk to the origin as the edge does: real SNI, but pinned to the origin address
openssl s_client -connect 203.0.113.10:443 -servername www.example.com \
  </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates

3. Confirm Whether the Edge Is Actually Verifying

A CDN configured to ignore origin certificate errors will happily serve a site whose origin certificate is expired, self-signed, or issued for a different hostname. That is a latent fault, not a working configuration — it fails the moment anyone tightens the setting or the provider changes its default. Check the setting explicitly and, where the origin certificate is not publicly trusted, fix the certificate rather than relaxing the verification.

# Ask the origin whether its chain validates against the public trust store
curl -sI --resolve www.example.com:443:203.0.113.10 https://www.example.com/ >/dev/null \
  && echo "origin chain validates" || echo "origin chain does NOT validate"

Read the SANs, not just the subject. The subject line often shows a single hostname while the certificate legitimately covers several through its subject alternative names, and it is the SAN list the edge matches against. A certificate whose subject looks wrong may be perfectly valid, and one whose subject looks right may still omit the exact name the edge sends — which is the specific failure in the worked example below.

4. Re-check Both After the Record Changes

Everything above is done before cutover against known addresses. Repeat it through the public hostname afterwards, because the path a request takes has changed and the edge may now be reaching a different origin than the one you tested.

# Post-cutover: through the real hostname, following the real path
openssl s_client -connect www.example.com:443 -servername www.example.com \
  -showcerts </dev/null 2>/dev/null | grep -E 'subject=|issuer=' | head -4
Two independent TLS connections in a CDN-fronted stack A visitor validating the edge certificate on the first connection, and the CDN edge separately validating the origin certificate on a second connection, with each failure producing a different symptom. Two handshakes, two certificates, two ways to fail Visitor validates the edge cert CDN edge validates the origin cert Origin presents its own chain TLS #1 TLS #2 TLS #1 broken: everyone sees it immediately loud, obvious, fixed within minutes TLS #2 broken: nobody sees it until strict verification is switched on The right-hand failure can sit dormant for months and then take the whole site down on a configuration change nobody connected to it. Test both connections separately — the public hostname only exercises the first.
Checking the site in a browser tests exactly one of these two connections, and it is the one that would have told you anyway.

Worked Example

The sequence below is a CDN adoption rather than an origin move — the case where the second connection is introduced for the first time and therefore has never been tested. A publisher moves its origin behind a new CDN. The edge certificate is provisioned automatically and validates cleanly, so the site loads and everyone signs off. The origin, meanwhile, is still presenting the certificate it had before — issued for the old hostname, and now serving requests for the new one.

Nothing breaks, because the CDN’s default origin setting accepts any certificate. Three weeks later an infrastructure engineer tightens that setting as part of unrelated hardening, and the entire site returns 526 within seconds:

$ curl -sI https://www.example.com/
HTTP/2 526
# Cloudflare 526: invalid SSL certificate presented by the origin

The fix takes four minutes — reissue the origin certificate for the correct hostname — but the diagnosis takes an hour, because nothing in the recent change history mentions certificates and the migration was declared complete weeks earlier. Running the step-2 check at cutover would have surfaced it while the migration was still the obvious suspect.

Origin verification modes and what each one hides Three CDN origin-verification settings compared by what they accept from the origin and the latent fault each one can conceal until the setting is changed. A permissive origin setting is a deferred outage Origin mode Accepts Hides Full (strict) a valid, matching chain only nothing — this is the goal Full (non-strict) any certificate, even self-signed wrong hostname, expired, self-signed Flexible plain HTTP to the origin that the origin has no TLS at all The bottom row also means traffic between edge and origin is unencrypted, which is a finding in its own right rather than a migration detail. Fix the origin certificate and move to strict — do not relax the setting to make a symptom disappear.
Every row below the first works perfectly right up until somebody moves it to the first, which is usually a security task rather than a migration one.

Record both certificates in the migration inventory alongside their authority, expiry and owner. The edge certificate is frequently provisioned and renewed automatically by the CDN while the origin’s is managed by hand, and the failure mode is assuming one process covers both. Two rows in a table, checked at the same cadence, removes an entire class of surprise nine months later.

Verification

Run both halves before the switch against known addresses, and again afterwards through the public hostname.

# 1. Edge chain is complete (>= 2 certificates)
openssl s_client -connect www.example.com:443 -servername www.example.com \
  -showcerts </dev/null 2>/dev/null | grep -c 'BEGIN CERTIFICATE'

# 2. Origin certificate is valid for the hostname the edge will send
openssl s_client -connect 203.0.113.10:443 -servername www.example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -ext subjectAltName -dates

# 3. A strict client completes the whole path end to end
curl -sSI https://www.example.com/ | head -1

A clean result is a count of two or more, an origin certificate whose SANs include the hostname the edge sends, and a 200 from a curl that has not been told to skip verification.

Which test exercises which connection Four checks mapped to the TLS connection each one actually tests, showing that a browser visit and a plain curl both exercise only the visitor-to-edge connection. Only one of these sees the origin connection Check Tests TLS #1 Tests TLS #2 Loading the site in a browser yes, leniently no curl against the hostname yes, strictly no openssl against the origin IP no yes You need at least two of these rows. Testing only through the public hostname leaves the origin connection entirely unexamined.
The third row is the check nobody runs, and the one that would have caught the worked example above at the moment it was introduced.

FAQ

Does the origin need a publicly trusted certificate, or will an internal one do? An internal one is fine provided the edge is configured to trust that authority specifically, which several providers support through an origin-CA feature. What does not work is an internal certificate with verification switched off — that is not a trust decision, it is the absence of one, and it accepts any certificate including one presented by something that is not your origin. Pick a trusted certificate or an explicitly configured private authority; do not pick neither.

Why does the edge send the public hostname as SNI rather than the origin’s own name? Because that is how the origin knows which site to serve. The edge is fetching content for www.example.com, so it sends that name, and the origin’s certificate has to cover it — which is why an origin certificate issued for an internal hostname fails even though the internal hostname resolves. Where the origin genuinely needs a different name, most CDNs let you override the SNI and the Host header separately; set both deliberately and certify whichever name you configure.

How does this change if the CDN also caches? It delays the symptom, which makes the origin failure harder to attribute. A cached response continues serving long after the origin has become unreachable, so a broken origin certificate can lie dormant until a cache entry expires or a purge is issued. That is another argument for testing the origin connection directly rather than inferring its health from the fact that the site is up.

Should the origin certificate be renewed on the same schedule as the edge one? Track them separately, because they usually come from different places — the edge certificate is often provisioned and renewed by the CDN automatically, while the origin’s is yours to manage. The failure mode is assuming the automated one covers both. List each certificate, its authority, its expiry and its owner in the same inventory, and alert on the origin’s expiry as loudly as on the edge’s even though its failure is quieter.

Related

← Back to TLS & Certificate Cutover