Skip to content

Cloudflare security headers, HSTS, HTTPS and HTML caching without breaking your site

Published 7 October 202610 min readBy the SmoothSeen editorial team

To set Cloudflare up properly, use Full (strict) encryption, turn on Always Use HTTPS and HSTS starting with a short max-age, and add security headers through a Response Header Transform Rule rather than the managed toggle, which still sends X-XSS-Protection and Expect-CT. HTML is not cached unless you create a Cache Rule.

Key points

  • Flexible encryption leaves the hop between Cloudflare and your server unencrypted, and if your server redirects to HTTPS it causes a redirect loop. With a certificate on the origin, use Full (strict).
  • Cloudflare's HSTS setting accepts a max-age of 1 to 12 months, and preload lists require at least 12. Removing HTTPS before it expires locks returning visitors out.
  • The managed "Add security headers" toggle adds X-XSS-Protection and Expect-CT, two headers MDN lists as deprecated. A Response Header Transform Rule of your own is the better option.
  • Cloudflare does not cache HTML or JSON by default: it caches by file extension. Caching HTML needs a Cache Rule that excludes sessions and the basket.

To check it on your own site: SEO audit

On this page

Cloudflare sits between your visitors and your server (the "origin"), so it can add HTTPS, headers and caching without you touching the server configuration. That is convenient, but there are traps: an encryption mode that does not encrypt the whole journey, a headers toggle that ships two deprecated headers, and a cache that does not store your pages by default. This guide follows Cloudflare's official documentation as of 7 October 2026.

What does Cloudflare handle, and what does your server still do?

Task
Certificate the visitor sees
In Cloudflare
Yes, the edge certificate
On your server
Not needed
Task
Encryption between Cloudflare and the origin
In Cloudflare
Set by the encryption mode
On your server
Needs its own certificate (public CA or Cloudflare Origin CA)
Task
HTTP to HTTPS redirect
In Cloudflare
Always Use HTTPS
On your server
Best not duplicated (loop risk)
Task
HSTS
In Cloudflare
Edge Certificates
On your server
Or here, but not in both places
Task
Other security headers
In Cloudflare
Response Header Transform Rules
On your server
Or here, with the same values
Task
HTML caching
In Cloudflare
Only with a Cache Rule
On your server
Decides what may be stored through Cache-Control
Task
Compression to the visitor
In Cloudflare
gzip, Brotli or Zstandard
On your server
Can send it already compressed

If you would rather keep this logic on the server, there are HTTPS, HSTS and header guides for Apache with .htaccess and for Nginx. The other half of Cloudflare, deciding which AI crawlers get in, is covered in the guide to Cloudflare and AI bots.

Step 1: the encryption mode, Full (strict) and never Flexible

The SSL/TLS encryption mode controls how two connections are encrypted: visitor to Cloudflare, and Cloudflare to your server. You change it under SSL/TLS > Overview1. The manual options are:

Mode
Off
Visitor → Cloudflare
HTTP
Cloudflare → origin
HTTP
When to use it
Never on a public site
Mode
Flexible
Visitor → Cloudflare
HTTPS
Cloudflare → origin
Unencrypted HTTP
When to use it
Only if the origin cannot do TLS at all
Mode
Full
Visitor → Cloudflare
HTTPS
Cloudflare → origin
HTTPS without validating the certificate
When to use it
Self-signed origin certificate, as a stopgap
Mode
Full (strict)
Visitor → Cloudflare
HTTPS
Cloudflare → origin
HTTPS with certificate validation
When to use it
Whenever the origin has a valid certificate

Why Flexible is a bad idea if your origin already has HTTPS. The hop between Cloudflare and your server travels in clear text, and if your server redirects HTTP to HTTPS, Cloudflare asks over HTTP, the server answers with a redirect to HTTPS, Cloudflare asks over HTTP again… and the site becomes unreachable in a redirect loop. Cloudflare says so in plain terms: do not use Flexible if the origin forces HTTPS, or if the site handles personal data or logins2.

Full (strict) requires the origin certificate to be unexpired, issued by a public authority or Cloudflare's Origin CA, and to match the hostname. If it fails, visitors see a 526 error3.

On migrated zones the default is Automatic SSL/TLS, which raises the mode to the most secure one your origin supports and never lowers it1. If you see "Automatic", check which mode it actually picked.

Step 2: Always Use HTTPS and HSTS

Always Use HTTPS redirects every http request to https, across all subdomains. It lives under SSL/TLS > Edge Certificates and only appears if the encryption mode is not Off4. Cloudflare advises against also redirecting on the server, to avoid loops4. Forcing HTTPS does not fix mixed content (images or scripts loaded over http://); Automatic HTTPS Rewrites handles part of that4.

HSTS (HTTP Strict Transport Security) is a header that tells the browser "for this long, only come here over HTTPS". You enable it under SSL/TLS > Edge Certificates > HTTP Strict Transport Security (HSTS) > Enable HSTS5. The dashboard offers:

  • Max Age: 1 to 12 months, or 0 to disable.
  • includeSubDomains: applies the policy to subdomains. Any subdomain without HTTPS becomes unreachable.
  • Preload: makes you eligible for browser preload lists, which require a max-age of at least 12 months.
  • No-Sniff: adds X-Content-Type-Options: nosniff.

The documentation's warnings are serious5. With HSTS on, do not switch DNS records to "DNS only", do not pause Cloudflare, do not move your nameservers away, do not redirect HTTPS to HTTP and do not let the certificate lapse: if HTTPS disappears before the max-age runs out, returning visitors cannot reach the site for that whole period.

The cautious order:

  1. Check that every subdomain answers over HTTPS.
  2. Start with the shortest max-age the dashboard allows (1 month), without includeSubDomains or Preload. For an even shorter trial, Cloudflare lets you send the header through a Response Header Transform Rule instead5, for example Strict-Transport-Security: max-age=86400; once it works, move to the dashboard setting and delete the rule.
  3. Go up to 12 months and only then consider includeSubDomains.
  4. Preload is hard to undo: it forces HTTPS on every subdomain in every browser, and getting off the list takes months. Turn it on only if you are certain.

Step 3: security headers, better with your own rule

Cloudflare has a toggle called Add security headers (under Rules > Settings > Managed Transforms)6. Today it adds exactly these five headers7:

x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN
referrer-policy: same-origin
expect-ct: max-age=86400, enforce

Two of them should not be there. MDN lists X-XSS-Protection as deprecated and non-standard, warns that it can create XSS vulnerabilities on otherwise safe sites, and recommends Content-Security-Policy instead8. Expect-CT is deprecated too: only Chromium-based browsers ever implemented it, and Chromium dropped it in version 1079. On top of that, referrer-policy: same-origin sends no referrer at all to other domains, which may annoy you if you track where outbound clicks come from.

So create your own Response Header Transform Rule10:

  1. Go to Rules > Overview and choose Create rule > Response Header Transform Rule.
  2. Give it a name ("Security headers").
  3. Under When incoming requests match, use a custom expression to scope it to your host: (http.host eq "www.example.com").
  4. Under Modify response header, choose Set static for each header. One rule can set up to 30 headers.
  5. Deploy.

The headers and values I suggest as a starting point:

X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Reporting-Endpoints: csp-endpoint="https://www.example.com/csp-reports"
Content-Security-Policy-Report-Only: default-src 'self'; img-src 'self' data: https:; frame-ancestors 'self'; report-to csp-endpoint

The CSP is in Report-Only mode: it watches for violations without blocking anything, which is exactly what MDN suggests for testing a policy before enforcing it11. Reports go to the Reporting-Endpoints URL, which must be a service of yours that accepts POST requests. Once the violations list is clean, rename the header to Content-Security-Policy.

Three caveats from the documentation12: you cannot modify headers starting with cf-; changing Cache-Control with these rules does not change how Cloudflare caches; and the rules also apply to Cloudflare's own error pages. If you use Cloudflare products that inject scripts, such as Rocket Loader or Web Analytics, your CSP must allow their domains; Cloudflare publishes the list13.

Step 4: caching, what Cloudflare stores and what it does not

Cloudflare caches by file extension, not by MIME type, and does not cache HTML or JSON by default14. It does cache CSS, JS, images (JPG, PNG, WEBP, AVIF, SVG), fonts (WOFF, WOFF2) and PDFs, among others. It also caches robots.txt by default, so if you change it and the change does not show, purge the cache.

It will not cache, whatever the extension, if the response carries Cache-Control with private, no-store, no-cache or max-age=0, if it carries Set-Cookie, or if the request is not a GET14.

Caching HTML with a Cache Rule

If your pages are the same for every visitor, caching HTML at the edge cuts server response time. You do it with a Cache Rule under Caching > Cache Rules: Cache eligibility > Eligible for cache. The Free plan allows 10 rules15.

Cloudflare spells out the risk: this option caches all HTML even when it contains dynamic content, and a visitor may receive information not meant for them16. Always exclude anything personal. An example for a WordPress shop, whose logged-in user cookie starts with wordpress_logged_in17:

(http.host eq "www.example.com"
 and not http.request.uri.path contains "/wp-admin"
 and not http.request.uri.path contains "/basket"
 and not http.request.uri.path contains "/my-account"
 and not http.cookie contains "wordpress_logged_in")

For Edge TTL, the cautious choice is Use cache-control header if present, use default Cloudflare caching behavior if not: your server stays in charge18. Be careful with Ignore cache-control header and use this TTL: if the response carries Set-Cookie, Cloudflare strips it and caches the page anyway19. That is how one customer's session page ends up served to another.

Browser Cache TTL

Browser Cache TTL sets how long the browser keeps each resource. The default is 4 hours, and Cloudflare overrides your server's headers if their value is lower or if it sends neither Cache-Control nor Expires20. If your server already sends good headers (say, one year for fingerprinted CSS and JS files), choose Respect Existing Headers under Caching > Configuration. Purging Cloudflare's cache does not clear what the browser already stored20.

Step 5: compression, and optimisations that can break scripts

By default Cloudflare compresses HTML, CSS, JavaScript, JSON, XML, SVG and several font formats with gzip, Brotli or Zstandard, depending on what the browser accepts and on your plan, and only on 200 responses (plus 403 and 404 errors)21. Compression Rules let you pick the algorithm per file type, and they are available on the Free plan too22. If your server sends Cache-Control: no-transform, Cloudflare leaves that response's compression alone21.

Rocket Loader defers all JavaScript until after the page has rendered. Cloudflare acknowledges the risk: if you see JavaScript or jQuery errors, turn it off and test again, and if you run a CSP, add ajax.cloudflare.com to script-src23. Test everything that relies on scripts (basket, forms, menus) before leaving it on.

How to check it

  1. Headers: run curl -sI https://www.example.com/ and look for strict-transport-security, x-content-type-options, content-security-policy-report-only and, if you enabled the managed toggle, the x-xss-protection you do not want.
  2. Cache: the cf-cache-status header tells you whether the response came from cache (HIT), was cacheable but not stored yet (MISS), was refused by the origin, for example through Set-Cookie (BYPASS), or was not cacheable (DYNAMIC)24. Request the same page twice: the second should be a HIT if the Cache Rule works. Repeat with the session cookie and check that it no longer is.
  3. Redirect: curl -sI http://example.com/ should return a single redirect to https://.
  4. External scores: Mozilla's HTTP Observatory grades your security headers, and PageSpeed Insights shows whether server response time improved once HTML was cached.

What SmoothSeen does with this

SmoothSeen checks whether your page answers over HTTPS, whether it redirects http to https and which security headers it sends, using Mozilla's HTTP Observatory. It also checks whether text arrives compressed with gzip or Brotli, and reports the real-user Core Web Vitals that PageSpeed Insights publishes, against Google's thresholds. It never logs in to your Cloudflare account: it sees what a visitor receives, which is what counts.

What to do this week

Open SSL/TLS > Overview and confirm the mode is Full (strict). Then check whether "Add security headers" is switched on and replace it with your own rule without X-XSS-Protection or Expect-CT. To see the result alongside speed and compression, run an SEO audit.

Frequently asked questions

Why do I get ERR_TOO_MANY_REDIRECTS after turning on Cloudflare?

Almost always it is Flexible mode with a server that already redirects to HTTPS: Cloudflare requests the page over HTTP, the server sends it to HTTPS and Cloudflare asks over HTTP again. Switch the encryption mode to Full (strict) if your server has a valid certificate, or to Full if it is self-signed while you get a proper one.

Does Cloudflare add HSTS automatically?

No. You have to enable it under SSL/TLS, Edge Certificates, and the dashboard asks you to confirm you understand the consequences. It sends the header only on HTTPS responses, with the max-age you choose, from 1 to 12 months. If your server already sends it, do not duplicate it in Cloudflare: keep one single place to change it.

Is it a good idea to cache all HTML in Cloudflare?

Only if pages are the same for everyone. A brochure site or a blog benefits; a shop with a basket and customer accounts needs to exclude those paths and the session cookies in the rule itself. Never force a cache time that ignores the server's headers on pages that can carry a user's session.

Does Rocket Loader improve Core Web Vitals?

Cloudflare says it improves paint metrics, such as first contentful paint, by deferring JavaScript, but its documentation gives no figures for LCP, INP or CLS, and it warns that it can cause JavaScript errors. Measure your own site with PageSpeed Insights before and after, check that the basket and forms still work, and switch it off if anything breaks.

Sources

  1. 1Encryption modes, Cloudflare Docs, updated 16 April 2026.
  2. 2Flexible, Cloudflare Docs, updated 1 September 2026.
  3. 3Full (strict), Cloudflare Docs, updated 9 July 2026.
  4. 4Always Use HTTPS, Cloudflare Docs, updated 14 August 2026.
  5. 5HTTP Strict Transport Security (HSTS), Cloudflare Docs, updated 14 August 2026.
  6. 6Configure Managed Transforms, Cloudflare Docs, updated 29 April 2026.
  7. 7Available Managed Transforms, Cloudflare Docs, updated 24 September 2026.
  8. 8X-XSS-Protection, MDN, updated 21 August 2026.
  9. 9Expect-CT, MDN, updated 27 August 2026.
  10. 10Create a response header transform rule in the dashboard, Cloudflare Docs, updated 5 May 2026.
  11. 11Content-Security-Policy-Report-Only, MDN, updated 22 March 2026.
  12. 12Response Header Transform Rules, Cloudflare Docs, updated 4 September 2026.
  13. 13Content Security Policies (CSPs), Cloudflare Docs, updated 20 April 2026.
  14. 14Default cache behavior, Cloudflare Docs, updated 14 September 2026.
  15. 15Cache Rules, Cloudflare Docs, updated 14 August 2026.
  16. 16Cache Level (Cache Everything), Cloudflare Docs, updated 13 October 2025.
  17. 17Cookies, WordPress Developer Resources, accessed 7 October 2026.
  18. 18Cache Rules settings, Cloudflare Docs, updated 16 September 2026.
  19. 19Head Requests and Set-Cookie Headers, Cloudflare Docs, updated 6 May 2026.
  20. 20Edge and Browser Cache TTL, Cloudflare Docs, updated 14 August 2026.
  21. 21Content compression, Cloudflare Docs, updated 17 April 2026.
  22. 22Compression Rules, Cloudflare Docs, updated 14 August 2026.
  23. 23Rocket Loader, Cloudflare Docs, updated 14 August 2026.
  24. 24Cloudflare cache responses, Cloudflare Docs, updated 4 September 2026.

How to cite this article

SmoothSeen. (2026, October 7). Cloudflare security headers, HSTS, HTTPS and HTML caching without breaking your site. https://smoothseen.com/en/blog/cloudflare-security-headers-caching/

Who writes this

SmoothSeen is a website audit tool that measures visibility in search engines and AI assistants and delivers reports under the agency's own brand.

This blog belongs to SmoothSeen: when an article discusses the product, it does so knowing the product is ours. Third-party figures link to their original source.

Change history

  • First version.

Keep reading

Cloudflare security headers, HSTS and HTML caching