# Cloudflare settings for speed and security, on the free plan

> The Cloudflare free-plan settings that make a report go green, in order, with what each one changes, the traps (Flexible SSL, cache everything, Rocket Loader) and how to verify from outside.

Updated 2026-09-25 · Other platforms · HTML version: https://getreport.app/guides/cloudflare-settings-for-speed-and-security

Cloudflare's free plan puts an edge with HTTP/3, Brotli, a firewall and free TLS in front of any site, and its dashboard has hundreds of switches. About fifteen of them change what a website report shows. This guide walks through those in the order that avoids breaking the site, says what each does to the findings, and ends with the checks that prove it worked from outside. Allow 45 minutes, including a purge and a re-test.

## Quick answer

- DNS record **proxied** (orange cloud), otherwise nothing below applies.
- SSL/TLS mode **Full (strict)**, never Flexible. Then Always Use HTTPS, Automatic HTTPS Rewrites, Minimum TLS 1.2, TLS 1.3 on, and HSTS once every subdomain works over HTTPS.
- Speed: Brotli on (default), Early Hints on, Rocket Loader **off** on most WordPress sites. Auto Minify no longer exists.
- Caching: leave the default (static files only). Use a Cache Rule for HTML only when the site has no logged-in visitors or carts, or use APO.
- Security: the free managed WAF ruleset, Bot Fight Mode, one rate-limit rule on the login path, and never a rule that challenges verified bots.
- Security headers: one Transform Rule (Modify Response Header) that sets each header.
- Verify with the [security headers checker](https://getreport.app/tools/security-headers), the [HTTP/2 test](https://getreport.app/tools/http2-test) and a cold and a warm TTFB measurement.

## Why the settings matter

Cloudflare is a proxy. Every visitor request goes to a Cloudflare data centre near them, which either answers from its cache or asks your server (the origin) and relays the answer. That position lets it terminate TLS, speak HTTP/3, compress, add headers and block bots without touching the origin. It also means a wrong setting affects every page at once, and that what your server sends is not necessarily what visitors receive.

Two settings do most of the damage on new setups. Flexible SSL talks plain HTTP to the origin, which produces redirect loops the moment the origin insists on HTTPS and leaves the last hop unencrypted. A "cache everything" rule caches HTML, which is wonderful on a brochure site and serves one shopper's cart to the next on a store. Both take one click to set and a support ticket to diagnose.

The rest are free wins: HTTP/3, Brotli, TLS 1.3, security headers, a firewall and a rate limit each take an afternoon on a server and a minute here, and the report shows every one of them.

## How getReport checks it

> **Free tool:** [Security headers checker](https://getreport.app/tools/security-headers): Check HSTS, CSP, X-Frame-Options, Referrer-Policy, Permissions-Policy and cookie flags on any site. Free, no signup, with a fix for every missing header.

The report sees Cloudflare from outside, as a visitor does, so it grades Cloudflare and the origin together. The HTTP/2 test makes a TLS handshake offering h2 and http/1.1 and records the protocol and TLS version the edge picks, reads the `Alt-Svc` header for HTTP/3, and loads the page in Chromium to count the responses per protocol. The CDN finding recognises Cloudflare from the `cf-ray` header, a `server: cloudflare` value or `cf-cache-status`; the Best practices module reads `content-encoding` on every text response for the compression finding and `Cache-Control` or `Expires` on every script, stylesheet, image and font for the cache finding. Security headers are read from the final response, so a header set in a Transform Rule counts exactly like one set on the origin.

![The protocol details table of the HTTP/2 test for an origin with no proxy in front: HTTP/2 not tested because the site answers over plain http, HTTP/3 not advertised, no Alt-Svc header, no TLS, and all 12 responses over http/1.1](https://getreport.app/guides/img/cloudflare-settings-for-speed-and-security/protocol.webp "The starting point: a plain-HTTP origin with no Alt-Svc and every file over HTTP/1.1. Once the proxy is on, these rows show the edge's protocols instead.")

> **Check: HTTP/3 is advertised via Alt-Svc.** HTTP/3 (QUIC) shortens the connection setup and copes better with flaky mobile networks. Servers announce it with an Alt-Svc header; without it browsers never try.
>
> 1. Enable HTTP/3 in your CDN or server (Cloudflare toggle, Caddy default, Nginx 1.25+ "listen 443 quic").
> 2. Make sure UDP port 443 is open in the firewall.

> **Check: Text files are compressed.** HTML, CSS and JavaScript shrink by 70–90% with gzip or Brotli. Sending them uncompressed wastes visitors' data and seconds, especially on mobile.
>
> 1. Enable Brotli (or gzip) for text types in your server, hosting panel or CDN; Cloudflare and most hosts have it as one switch.
> 2. Check the files in the technical detail; third-party ones need the vendor to fix it.

> **Check: Strict-Transport-Security header is set.** HSTS tells browsers to always use HTTPS for your site, so after the first visit a typed address or an old http:// link never starts on an unencrypted connection. Only the preload list covers the very first visit.
>
> 1. Send the header: Strict-Transport-Security: max-age=31536000; includeSubDomains.
> 2. Start with a shorter max-age (e.g. 86400) if you are not sure every subdomain supports HTTPS.

> **Check: Static files have a cache lifetime.** Without a cache lifetime, every visit downloads the same logo, CSS and scripts again. Returning visitors should get them from their browser in 0 ms.
>
> 1. Send Cache-Control: public, max-age=31536000, immutable for versioned images, CSS, JS and fonts.
> 2. Most caching plugins and CDNs set this for you; check the "browser cache" or "edge TTL" setting.

The `Server` header finding passes once the proxy is on, because Cloudflare replaces the origin's `Server` value with `cloudflare`, which carries no version. `X-Powered-By` passes through from the origin unless you remove it with the "Remove X-Powered-By headers" Managed Transform.

## Step by step

### 1. Proxy the DNS record

DNS → Records. The `A` or `CNAME` records for the root and `www` need the orange cloud ("Proxied"). A grey cloud ("DNS only") means Cloudflare answers the DNS query and nothing else: no edge TLS, cache, firewall or HTTP/3, and the report shows whatever the origin does. Subdomains you do not want proxied (mail, FTP) stay grey.

Once proxied, the origin's IP is hidden and every setting below applies.

### 2. SSL/TLS: Full (strict), then the encryption switches

SSL/TLS → Overview. The modes are Off, Flexible, Full and Full (strict). Flexible serves HTTPS to visitors and fetches from your origin over plain HTTP. If the origin redirects HTTP to HTTPS, as it should, the visitor gets an endless loop: Cloudflare asks over HTTP, the origin says "go to HTTPS", Cloudflare asks over HTTP again. The origin also sees `http://` and prints `http://` asset URLs, which is mixed content.

**Full (strict)** encrypts both hops and checks the origin's certificate. The origin needs a valid certificate: a free Let's Encrypt one, or a Cloudflare Origin CA certificate (SSL/TLS → Origin Server → Create Certificate), which browsers would not trust directly but Cloudflare does, and which lasts up to 15 years. Set the mode to Full (strict) and open the site; a 526 error means the origin certificate is invalid, a 525 means the handshake failed.

Then SSL/TLS → Edge Certificates:

- **Always Use HTTPS**: on. Cloudflare answers every `http://` request with a 301 to `https://` at the edge; the report's http-to-https finding passes and the origin never sees plain HTTP.
- **Automatic HTTPS Rewrites**: on. Rewrites `http://` asset URLs in the HTML to `https://` when the host is known to support it; a safety net for the mixed-content finding, not a replacement for fixing the URLs.
- **Minimum TLS Version**: 1.2. The report's TLS check makes a deliberate TLS 1.0/1.1 handshake and expects a refusal.
- **TLS 1.3**: on.
- **HSTS**: on, after step 3.

### 3. HSTS, with the warning

HSTS tells browsers to refuse plain HTTP for your domain for `max-age` seconds. Cloudflare (SSL/TLS → Edge Certificates → HTTP Strict Transport Security) makes you acknowledge a warning first, because the setting is sticky: a browser that has seen the header cannot reach an HTTP-only subdomain until the time runs out, and if you leave Cloudflare the origin must keep serving valid HTTPS.

Enable it with "Max Age" at 6 months, "Apply HSTS policy to subdomains" only when every subdomain (including the grey-cloud ones) answers over HTTPS, and "Preload" only after reading [HSTS safely and the preload list](https://getreport.app/guides/hsts-safely-and-the-preload-list). Keep one source: if the origin also sends the header, remove it there.

### 4. Speed → Optimization

The Content Optimization tab has the three that matter:

- **Brotli**: on by default. Cloudflare compresses text responses at the edge whether or not the origin did, so the compression finding passes even for an origin with gzip off. The exception is a `Cache-Control: no-transform` header from the origin, which tells Cloudflare not to touch the response.
- **Early Hints**: on. Cloudflare remembers the `Link: rel=preload` and `preconnect` headers your origin sent and replays them as a `103` response while the origin works, so the browser fetches CSS and fonts earlier.
- **Rocket Loader**: **off** on WordPress and any site with inline scripts that expect to run in order. It defers every `<script>` until after the page, which improves lab scores and breaks sliders, forms and consent banners. If a script breaks after enabling Cloudflare, this is the first suspect.

**Auto Minify** was removed in 2024; minification belongs in the build step or the caching plugin.

### 5. Caching

Caching → Configuration. Two settings and one rule:

- **Caching Level**: Standard. Cloudflare caches static file extensions (images, CSS, JS, fonts), not HTML unless a rule says so.
- **Browser Cache TTL**: "Respect Existing Headers" when the origin already sends `Cache-Control`, as any caching plugin or the configs in [Cache-Control for humans](https://getreport.app/guides/cache-control-for-humans) do. A value instead overrides the origin, which is the quick fix when the origin sends nothing, and the reason a static file sometimes shows a lifetime the origin never set. The report reads what reaches the browser.
- A **Cache Rule** (Caching → Cache Rules) per path is the modern way to say "cache `/wp-content/uploads/*` for a year at the edge and in the browser". Cache Rules set eligibility, edge TTL and browser TTL separately.

The trap is a rule with "Cache everything" or "Eligible for cache" on all paths. Cloudflare then caches HTML, including the HTML it fetched for a logged-in editor or a shopper with a cart, and serves it to the next anonymous visitor. On a brochure site with no logins it is the biggest TTFB win available; on WordPress with users, WooCommerce or any personalised page it needs bypass rules for the cookies (`wordpress_logged_in`, `woocommerce_items_in_cart`, `wp-postpass`) placed above the caching rule, plus a purge after every publish. [CDN basics: what it fixes and what it does not](https://getreport.app/guides/cdn-basics-what-it-fixes-and-what-it-does-not) covers those rules.

After any deploy, theme change or plugin update: Caching → Configuration → Purge Cache, by URL for one page or "Purge everything" after a redesign. Development Mode bypasses the cache for three hours while you work.

### 6. Security

Security on the free plan:

- **WAF → Managed rules**: the Cloudflare Free Managed Ruleset is on by default and blocks widely exploited request patterns. Leave it on.
- **Bots → Bot Fight Mode**: on. It challenges traffic that Cloudflare classifies as automated and leaves verified bots (Googlebot, Bingbot and the other crawlers Cloudflare validates) alone.
- **WAF → Rate limiting rules**: the free plan includes a rule with a short window. Spend it on the login path: `(http.request.uri.path eq "/wp-login.php")`, a low request count per period, action Block. The [bot protection guide](https://getreport.app/guides/rate-limiting-and-bot-protection-on-a-small-site) has the full rule and the `xmlrpc.php` companion.
- **Security Level**: Medium. "I'm Under Attack" mode challenges every visitor, including crawlers that cannot solve it; use it during an attack only.
- **Challenge Passage**: 30 minutes, how long a solved challenge lasts, is fine.

Never write a custom WAF rule that challenges or blocks "all bots". Add `and not cf.client.bot` to any rule that targets automated traffic so verified crawlers pass, or pages start falling out of Google.

### 7. Security headers with Transform Rules

Rules → Transform Rules → Modify Response Header → Create rule. One rule, "All incoming requests", with one "Set static" line per header:

```text
Strict-Transport-Security   (leave to the HSTS setting in step 3)
Content-Security-Policy     default-src 'self'; img-src 'self' data: https:; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
X-Content-Type-Options      nosniff
X-Frame-Options             SAMEORIGIN
Referrer-Policy             strict-origin-when-cross-origin
Permissions-Policy          camera=(), microphone=(), geolocation=(), payment=()
```

"Set" overwrites a header the origin already sends; "Add" appends a second copy, which is what you do not want for `X-Frame-Options`. Cloudflare's Managed Transforms toggle ("Add security headers") sets a fixed subset in one click; use one or the other. Start the CSP as `Content-Security-Policy-Report-Only` and watch the browser console for a week before enforcing.

### 8. Redirects: Rules, not Page Rules

The older Page Rules (three on the free plan) are being replaced by the newer Rules products. For a www decision use Rules → Redirect Rules with a single dynamic rule: when hostname equals `www.example.com`, redirect to the expression `concat("https://example.com", http.request.uri.path)` with status 301 and "Preserve query string" on. Because Always Use HTTPS also redirects at the edge, check that the two do not stack into `http://www` → `https://www` → `https://` (two hops); the redirect checker shows every hop.

### 9. APO for WordPress

Automatic Platform Optimization is a paid add-on (a few dollars a month on the free plan) that works with the Cloudflare WordPress plugin. It caches HTML at the edge, purges when you publish, and bypasses the cache for logged-in users and WooCommerce cookies on its own: the "cache everything" rule from step 5 done properly. It is the biggest TTFB improvement for WordPress on modest hosting, and the only paid feature in this guide.

### 10. What Cloudflare does not fix

The proxy makes bytes arrive faster, not fewer. It cannot fix:

- **Origin TTFB on a cache miss.** Without HTML caching, every page request still runs your PHP; Cloudflare relays the wait.
- **Render-blocking CSS and JavaScript**, long tasks, a 2 MB hero image, layout shift. Those happen in the browser or in the theme. (Polish, which compresses and converts images, is on paid plans.)
- **Third-party scripts** the page loads from other hosts.

If the speed panel still shows LCP over 2.5 s after this guide, the fix is in the page (see [Largest Contentful Paint](https://getreport.app/learn/largest-contentful-paint)), not in the dashboard.

## Verify

1. **Security headers checker**: every header finding passes; the `Server` finding passes (`cloudflare`), HSTS shows the max-age you chose.
2. **HTTP/2 test**: the protocol table shows h2 negotiated, HTTP/3 advertised via `Alt-Svc`, TLS 1.3; the CDN finding names Cloudflare; the compression finding passes; the cache finding lists no static file without a lifetime.
3. **Cold and warm TTFB.** The first request after a purge is a cache miss and measures the origin; the next is what visitors get. Run the TTFB test right after the purge, then Re-run from the full report for the warm figure. For an immediate pair, run `curl -so /dev/null -w "%{time_starttransfer}\n" https://example.com/` twice. `curl -sI https://example.com/ | grep -i cf-cache-status` shows `HIT` on a cached file and `DYNAMIC` on HTML that is not cached (the default).
4. **The site still works**: log in, add to cart, submit a form, in a private window with the cache warm.

## Common mistakes

- **Flexible SSL.** Symptom: "too many redirects" or mixed-content warnings the moment the origin enforces HTTPS. Fix: an origin certificate and Full (strict).
- **Cache everything on a dynamic site.** Symptom: visitors see someone else's cart or the admin bar; edits do not show until a purge. Fix: bypass rules for the login and cart cookies above the cache rule, or APO, or no HTML caching at all.
- **Rocket Loader breaking scripts.** Symptom: a slider, form or consent banner fails only through Cloudflare. Fix: turn it off.
- **Challenging all bots.** Symptom: pages drop from Google; Search Console reports "blocked" fetches. Fix: exclude `cf.client.bot`, keep Security Level at Medium, and never leave "I'm Under Attack" on.
- **Forgetting to purge after a deploy.** Symptom: old CSS with the new HTML for hours. Fix: purge in the dashboard or from the caching plugin; add it to the deploy checklist.
- **A DNS-only record for the host that matters.** Symptom: the report shows the origin's `Server` header, no HTTP/3 and no CDN despite "having Cloudflare". Fix: orange cloud on the root and `www`.
