Skip to main content

Command Palette

Search for a command to run...

Your Customer Thinks Their Site Has HTTPS. It Probably Doesn't.

A presales story about the Cloudflare SSL setting almost everyone gets wrong — and how to verify, with proof, that you've actually fixed it.

Updated
12 min read
Your Customer Thinks Their Site Has HTTPS. It Probably Doesn't.
D
Cloud presales architect — anonymized war stories and frameworks on cloud architecture, security, and the trade-offs that shape real systems.

The Misconception That Lives Behind the Orange Cloud

If you believe you are protected just because you proxied your domain through Cloudflare and "SSL is in place," you are doing half the work. And in cyber security, half the work is no work.

Here's why.

When you put Cloudflare in front of your website, two distinct network connections come into existence — not one:

  • Visitor → Cloudflare — the browser talks to Cloudflare's edge.

  • Cloudflare → Origin — Cloudflare talks to your actual server (your VM on AWS, Hetzner, your hosting provider, wherever it lives).

The padlock you see in the browser bar reflects only the first connection. It tells the user nothing — absolutely nothing — about what happens between Cloudflare and your origin server.

Most teams configure the first connection correctly and never look at the second one. And that's where the breakdown lives.

If the second leg is unencrypted, your traffic — login credentials, customer PII, session tokens, payment data, whatever flows through — passes through every router, ISP, and intermediate network between Cloudflare's data center and yours, in plaintext. A man-in-the-middle on any of those hops can read it, modify it, or sell it on the dark web. We hear about these breaches every quarter. This is one of the ways they happen.

The Cloudflare SSL Modes — and Which One You're Actually On

Cloudflare offers five SSL/TLS settings — one automatic and four manual. Most teams never look past the one they picked on day one, and that early choice is usually wrong for production.

1. Automatic — This is now Cloudflare's default mode, and it's quietly impressive engineering. For years Cloudflare ran a separate tool called SSL Recommender that scanned each origin's TLS capability and prompted the user to pick the safest setting. Most users ignored the prompts. So Cloudflare went a step further: Automatic mode now performs that same check on every site by default. The moment it detects an origin that can handle TLS, it upgrades the connection to Full (option 4 below) — without breaking the site or surfacing a single certificate error to the user. It's the kind of pragmatic engineering most platforms don't bother to ship.

2. Off — No encryption anywhere. Self-explanatory. Don't use this in production.

3. Flexible — Encrypted from visitor to Cloudflare. Plaintext from Cloudflare to your origin. This is the trap. The browser shows the padlock. The user feels safe. Your traffic is exposed on the back half of the journey.

4. Full — Encrypted both legs. But Cloudflare does not validate your origin's certificate. A self-signed certificate works. So does an expired one. So does an attacker's certificate if they manage to intercept the connection. Better than Flexible — but still vulnerable to man-in-the-middle (MitM) attacks. If you assume no one would bother running such an attack on your traffic — that assumption is exactly the false sense of security this mode creates.

5. Full (Strict) — Encrypted both legs and Cloudflare validates the origin's certificate against a trusted chain. This is real end-to-end TLS. This is what your CTO thinks you have when they say "we're on HTTPS via Cloudflare."

Most teams I work with are on Flexible or Full when they think they are on Full (Strict). They click the orange cloud, see the padlock, ship, and move on.

What the CTO Thought vs. What Actually Happened

Here is the picture the CTO had in his head:

End-to-end encryption — Full (Strict) mode

This is Full (Strict) mode. End-to-end (E2E) TLS. The architecture is sound. No plaintext anywhere on the wire.

Here is what was actually configured:

Flexible mode — traffic exposed between Cloudflare and origin

This is Flexible mode. The encrypted leg ends at Cloudflare's edge. From Cloudflare onwards, the traffic flows in clear plain text across the public internet to wherever the origin lives.

The terminology we use in security — "end-to-end encryption (E2E)" — was not fulfilled. The architecture was not secure. And finding the origin to attack it is not hard: an attacker can pull historical DNS records, scan certificate transparency logs, or use a handful of well-known reconnaissance techniques to identify the hosting data center, then probe the network path for an exposed link.

For any enterprise that genuinely needs to protect data in transit — and that means anyone handling cardholder data under PCI DSS, healthcare data under HIPAA, or personal data under GDPR/ISO-27018 — Full (Strict) is the only correct setting. The others are not options. They are gaps.

I Want to Honor Cloudflare Here

The work those engineers do is excellent. Cloudflare has done more to make HTTPS accessible to the average website than almost any other company on the internet.

The reason Flexible mode exists is practical: many origins genuinely cannot run TLS on day one, and Cloudflare offers Flexible so those sites can still get partial protection while they figure the rest out. If Cloudflare forced Full (Strict) as a default, a large share of new users would hit complex certificate errors on day one and walk away. The setting exists for a real reason.

The core issue is that teams pick it as a permanent solution, and tell themselves they are "fully encrypted". I once flagged this exact pattern at another organization — only to find that their third-party security audit had missed it entirely, with the "encryption in transit" checkbox ticked clean in the final report.

Whenever I sit with a customer, I push to understand the traffic flow from origin to destination — every hop, every termination, every place encryption begins and ends. That single discipline surfaces more architecture problems and produces better solutions than almost any other discovery exercise I do.

How to Actually Fix This

If you read this and you don't know which mode you're in, you're probably not on Full (Strict). Here is how to get there.

Step 1: Generate an origin certificate.

The easiest path is Cloudflare's Origin CA. It's free, available from inside your Cloudflare dashboard under SSL/TLS → Origin Server → Create Certificate, and the certificate is valid for up to 15 years. The defaults are fine: RSA 2048, hostnames yourdomain.com and *.yourdomain.com.

When the certificate generates, Cloudflare will display two text blocks: the Origin Certificate and the Private Key. Save both to plain text files immediately. Cloudflare will never show the private key again, and losing it means regenerating from scratch.

Step 2: Install the certificate on your origin server.

For nginx, point ssl_certificate and ssl_certificate_key at the new files and reload. For Apache, the equivalent SSLCertificateFile and SSLCertificateKeyFile directives. On managed hosts like Hostinger, look for SSL → Install Custom SSL, paste the certificate and private key into the corresponding fields, and leave the CA bundle field empty. Cloudflare Origin Certificates do not require a CA bundle because they are not meant to be publicly trusted — only Cloudflare's infrastructure trusts them. That's the whole point.

Step 3: Switch the Cloudflare SSL/TLS mode to Full (Strict).

In your Cloudflare dashboard, navigate to SSL/TLS → Overview, and select Full (Strict). This is the single click that matters most. If your origin certificate is installed correctly, your site will continue loading without errors. If it isn't, you'll see a 525 SSL Handshake Failed error — which is itself a useful signal that the cert install needs revisiting.

Step 4: Verify with curl.

This step is where most tutorials stop and where mine starts. Open a terminal and run:

curl -vk --head --resolve yourdomain.com:443:YOUR_ORIGIN_IP https://yourdomain.com

The --resolve flag tells curl to bypass Cloudflare and connect directly to your origin server's IP, while still requesting your domain name. The -k flag tells curl to proceed even if the certificate is not trusted by your local machine.

You should see two things in the output:

  • A successful TLS handshake followed by HTTP/1.1 200 OK (or whatever status your homepage returns)

  • Response headers identifying your origin — for example, Server: LiteSpeed, platform: hostinger, or whatever your stack reports

Here's the output:

* Trying 141.xxx.xx.xxx:443...
* Connected to yourdomain.com (141.xxx.xx.xxx) port 443
< HTTP/1.1 200 OK
< Server: LiteSpeed
< platform: hostinger
< X-LiteSpeed-Cache: hit
< alt-svc: h3=":443"; ma=2592000

The handshake succeeded over TLS, the origin returned a clean 200, and the response identifies Hostinger's LiteSpeed server. That confirms the Cloudflare Origin Certificate is installed and being served correctly.

Now run the same command without the -k flag:

curl -v --resolve yourdomain.com:443:YOUR_ORIGIN_IP https://yourdomain.com

You should now see a failure with this kind of error:

schannel: SEC_E_UNTRUSTED_ROOT (0x80090325) - The certificate chain was issued by an authority that is not trusted.

This error is not a bug. It is the verification.

What it means: the Cloudflare Origin Certificate is signed by Cloudflare Origin CA, which is intentionally not trusted by browsers, operating systems, or any public PKI. Only Cloudflare's edge servers trust it. So, when you connect directly to your origin, your local machine correctly says "I don't recognize this CA, refusing to trust this connection."

That's exactly the design. It means:

  • Random visitors who somehow discover your origin IP and try to connect directly will be rejected by their own TLS clients

  • Only traffic flowing through Cloudflare will accept the certificate and proceed

  • Combined with Full (Strict) at the edge, you now have a closed loop — Cloudflare trusts only your origin cert, and only Cloudflare's edge talks to your origin

If you ran this curl test and the TLS handshake succeeded without -k, that means your origin is serving a publicly trusted certificate (Let's Encrypt, your host's default SSL, etc.) — which is fine but means you have not yet swapped to the Cloudflare Origin Certificate. Go back and reinstall.

Step 5 (bonus): Lock the origin down further.

Enable Authenticated Origin Pulls in Cloudflare so your origin will refuse any connection that does not present a Cloudflare client certificate. Combined with Full (Strict), this gives you mutual TLS between Cloudflare and your origin — even an attacker who got hold of your origin IP and somehow worked around the cert validation problem could not establish a connection.

The whole exercise takes an experienced engineer about an hour. Most teams put it off for years.

"But My Browser Shows a Different Certificate Than the One I Installed"

This is the question every careful reader asks after walking through the fix. I asked it myself.

You install the Cloudflare Origin Certificate on your server. You set Full (Strict). You open your site in a browser, click the padlock — and see a certificate issued by Let's Encrypt, not Cloudflare.

Did the installation fail? No. This is correct, and here's why:

There are two certificates in this architecture, serving two different connection legs:

Two certificates — visitor-facing Let's Encrypt and origin-facing Cloudflare Origin CA
  • Cert A (visitor-facing): Cloudflare automatically issues and presents this to your browser, via Let's Encrypt or Google Trust Services. It's publicly trusted. It's the cert your browser sees.

  • Cert B (origin-facing): The Cloudflare Origin Certificate you installed on your server. Cloudflare uses it when it talks to your origin. Browsers never see this certificate. They have no reason to.

So, when you click the padlock and see Let's Encrypt — that's Cert A doing its job. The Origin Certificate (Cert B) is invisible to the browser by design. The curl test in Step 4 is the only direct way to confirm it from outside Cloudflare.

If you don't internalize this two-certificate model, you'll be confused. Once you see it clearly, every other Cloudflare configuration question gets easier.

What Happened After

I explained all of this to the CTO and his team in that room. We walked through the modes. We drew the diagrams. We mapped what they had against what they thought they had.

The CTO was thankful. The team was thankful. Within a week they had moved to Full (Strict), enabled Authenticated Origin Pulls, and added an item to their security review checklist so this would never sit unaddressed again.

Honestly, moments like that bring me great joy. The job of a cloud presales solutions architect is not to sell the biggest possible solution. It is to ask the one question that turns a confident "we are secure" into an honest "we have work to do" — and then to help them do that work.

If you take only one thing from this article, take this: the padlock in the browser is not a guarantee of end-to-end encryption. It is a guarantee that the browser is talking to something over TLS. What that something does next is up to you to verify.

A Question to Ask in Your Next Architecture Review

The next time someone tells you "we're HTTPS, we're on Cloudflare," ask them this:

"What SSL/TLS mode are you running in Cloudflare — Off, Flexible, Full, or Full (Strict)? And have you verified the origin certificate with curl?"

If they don't know the answer to the first half, you already know the answer. They're not on Full (Strict). If they look puzzled at the second half, they haven't verified the fix even if they claim it's in place.

Help them get there. The curl one-liner takes thirty seconds and removes all ambiguity.


Originally published on quabin.com — I write about the questions I ask in real customer rooms, the ones that change architectures and surface the problems no one else noticed.