Cloudflare supports four SSL/TLS modes. Each one describes how traffic is encrypted between the visitor, Cloudflare and your server. Picking the wrong one causes either an endless redirect loop or an unencrypted leg between Cloudflare and the server — an open channel for stealing passwords and session cookies, even while the visitor's browser shows a padlock in the address bar.
The SSL/TLS modes
| Mode | Browser to CF | CF to server | When to use it |
|---|---|---|---|
| Off | HTTP | HTTP | Never |
| Flexible | HTTPS | HTTP | No SSL on the server (bad) |
| Full | HTTPS | HTTPS (any certificate) | Self-signed certificate |
| Full (Strict) | HTTPS | HTTPS (valid certificate) | Recommended |
Why Full (Strict) is the right choice
- Traffic is encrypted along the entire path, not just from the browser to the CDN.
- It protects against man-in-the-middle attacks between Cloudflare and the server — critical when the server is not in your own data center.
- It is the production security baseline: it matches PCI DSS requirements and most security policies.
How to turn on Full (Strict)
Cloudflare Dashboard → SSL/TLS → Overview → Full (strict). The server needs a valid SSL certificate — Let's Encrypt or a Cloudflare certificate both work.
Use a Cloudflare Origin Certificate instead of Let's Encrypt for maximum reliability: SSL/TLS → Origin Server → Create Certificate. It is valid for 15 years and is trusted only by Cloudflare, so the site will not open directly by IP through it — an extra layer of protection for the origin server.
Common errors explained
Codes 520-526 in a Cloudflare response are almost always tied to the SSL/TLS mode; the full list of codes is covered in the article on Cloudflare errors 520-525.
- ERR_TOO_MANY_REDIRECTS — the server is set to redirect HTTP to HTTPS while Cloudflare, in Flexible mode, connects to the server over HTTP: the result is an endless "redirect to HTTP to redirect" loop.
- ERR_SSL_VERSION_OR_CIPHER_MISMATCH — the origin server has modern TLS 1.2/1.3 protocols disabled, or an outdated OpenSSL does not support the ciphers Cloudflare needs for the handshake.
- 521 Web Server Is Down under Full (Strict) — the server only listens on HTTP port 80 while HTTPS on port 443 does not respond: Cloudflare tries to reach it over HTTPS and gets a connection refused.
- 526 Invalid SSL Certificate — the certificate on the server is expired, self-signed or issued for the wrong domain, while the mode is set to Full (Strict), which requires a valid chain.
- 525 SSL Handshake Failed — Cloudflare could not agree with the server on a TLS protocol during the handshake; the usual cause is the server disabling every protocol Cloudflare supports, or port 443 being taken by another service.
Comparing origin certificate sources
| Source | Validity period | Trusted outside Cloudflare | Auto-renewal |
|---|---|---|---|
| Let's Encrypt | 90 days | Yes, a public CA | Through certbot / cron |
| Cloudflare Origin CA | 15 years | No, Cloudflare only | Not needed |
| Self-signed | Whatever you set | No | Manual |
Forcing HTTPS through Cloudflare
SSL/TLS → Edge Certificates → Always Use HTTPS → On. Cloudflare will redirect HTTP to HTTPS at the CDN layer, before the request ever reaches the server — this takes the load off the origin and removes the risk of a broken redirect inside the application.
When Full (Strict) does not fit
- The server is still being set up and has no valid certificate yet — temporarily use Full with a self-signed one, but never Flexible, so traffic is not sent in plain text.
- The origin sits behind a dynamic IP with no DNS record to issue Let's Encrypt against — then the only practical option is a Cloudflare Origin Certificate bound to the IP rather than the domain.
- A legacy application strictly checks the certificate name and does not understand a certificate from a non-standard CA — sometimes Full has to stay in place instead of Strict until the application is updated.
How to verify the mode is set correctly
# Check the certificate an external client sees
curl -vI https://example.com/ 2>&1 | grep -E 'SSL|subject|issuer'
# Confirm HTTP redirects to HTTPS in a single hop
curl -I http://example.com
# Expect: HTTP/1.1 301, Location: https://example.com/
# Check the server certificate directly, bypassing Cloudflare (via the hosts file)
curl -vI --resolve example.com:443:SERVER_IP https://example.com/ 2>&1 | grep issuer
If the first command shows a Cloudflare certificate, the second shows a single redirect with no loop, and the third confirms a valid certificate on the server itself, Full (Strict) is set up correctly.
Never use Flexible if HTTPS is already set up on the server. It creates a redirect loop: Cloudflare connects over HTTP, the server redirects to HTTPS, Cloudflare connects over HTTP again — until the browser gives up with ERR_TOO_MANY_REDIRECTS.