How to apply Cloudflare cache rules for Magento (and write them by hand)
Apply the six OCM Labs Cloudflare cache rules for Magento from the admin or CLI with a dry-run diff, or paste the exact expressions by hand.

Cloudflare will not cache your Magento HTML until a cache rule tells it to. Out of the box the edge caches static file types and passes everything else to the origin, so cf-cache-status: DYNAMIC on a category page is the default state, not a bug. You need a rule that makes storefront HTML eligible for cache, plus bypass rules under it so checkout, account pages and POSTs never land in the edge cache.
The tempting shortcut is one "Cache Everything" rule. It is the wrong rule: it ignores Magento's private, no-store headers, so checkout and account pages get cached and served to the next visitor. The rules below respect origin headers, so Magento's Cache-Control still decides what is cached and for how long.
OCM Labs Cloudflare, a free and open source Magento module, writes six Cloudflare cache rules for Magento to your zone, shows a diff first, and documents the expressions so you can paste them yourself.
Step 1: Check the token and the ACL
Applying needs an API token with Zone:Cache Rules:Edit (separate from Zone:Settings:Edit, and the one people miss) and, from the admin, the OCMLabs_Cloudflare::settings_write ACL resource. If you cannot add Zone:Cache Rules:Edit to the token, skip to step 3.
Step 2: Apply from the admin or the CLI
From the admin, open System > Cloudflare > Dashboard > Health and click Apply recommended cache rules. From the shell:
bin/magento ocmlabs:cloudflare:rules:apply --dry-run
bin/magento ocmlabs:cloudflare:rules:applyRun the dry run first. It prints the diff the apply would make:
- Kept: rules that stay as they are. Your own rules always land here.
- Added:
[OCMLabs]rules the zone does not have yet. - Changed:
[OCMLabs]rules whose expression or actions differ from what the module wants. - Removed:
[OCMLabs]rules the current settings no longer need, for example the vary cookie bypass after switching Vary Handling to Cache key.
Read the kept list for a note saying one of your rules sits above the module's rules and might override them. Put your own rules below the OCMLabs rules unless you mean the override.
Run the real apply once the diff looks right. Running it twice changes nothing the second time.
How the naming keeps websites apart
The module only touches rules whose description starts with [OCMLabs]. Each name ends with the Magento website code, for example [OCMLabs] Cache storefront HTML (base), so several websites can share one zone: applying the rules for one website leaves the other websites' [OCMLabs] rules, and all of your own, alone.
The six rules in order
Cloudflare evaluates cache rules top to bottom, and a later match overrides an earlier one for each setting it sets. So the bypass rules have to sit below the cache rule, and the "Bypass rules" health check confirms they do. This is the order the module writes.
| RULE | WHAT IT DOES | |
|---|---|---|
| 1 | Cache storefront HTML | Everything on the storefront hosts is eligible for cache. Edge TTL and browser TTL respect the origin headers. |
| 2 | Static assets | /static/ and /media/ are cached for a year at the edge and in the browser. Magento versions static URLs and image variants live at their own paths, so this is safe. |
| 3 | Bypass protected paths | Every path in Bypass Paths, plus the ___store= and ___from_store= store switch URLs. |
| 4 | Bypass non-GET | Anything that is not a GET request. |
| 5 | Bypass on vary cookie | Requests carrying the X-Magento-Vary cookie. Only written when Vary Handling is Bypass. |
| 6 | Bypass query strings | Requests with a query string, except static and media paths. Only written when Cache Query Strings is No. |
Rules 5 and 6 depend on the Edge Cache settings. Change Vary Handling or Cache Query Strings and the next dry run shows the rule being added or removed.
The Enterprise cache key variant
With Vary Handling set to Cache key on an Enterprise zone, rule 5 is replaced by a custom cache key on rule 1 that includes the X-Magento-Vary cookie, so store views, currencies and customer groups are cached as separate variants. On any other plan the module falls back to the bypass rule and says so in the preview.
Step 3: Write the rules by hand
Use this when the token lacks Zone:Cache Rules:Edit, or to see exactly what the module writes. In Cloudflare go to your zone > Caching > Cache Rules > Create rule. For each rule choose Edit expression, paste the expression and set the actions listed.
Before you paste:
- Replace
www.example.comwith your storefront host. For several hosts, list them inside the braces separated by spaces:{"www.example.com" "example.com"}. - Replace
/adminin rule 3 with your real admin path (thefrontNameinapp/etc/env.php). - Rule 3 uses the default Bypass Paths. If you changed that list, change the expression to match. Each path needs both the
eqterm and thestarts_withterm. - Name each rule exactly as shown, starting with
[OCMLabs]and ending with your website code in brackets. If you later grant the tokenZone:Cache Rules:Editand runrules:apply, the module takes over those rules for that website and leaves everything else alone.
1. [OCMLabs] Cache storefront HTML (base)
(http.host in {"www.example.com"})- Cache eligibility: Eligible for cache
- Edge TTL: Use cache-control header if present (respect origin)
- Browser TTL: Respect origin TTL
- Enterprise with Vary Handling set to Cache key only: Cache key > Cookie > include
X-Magento-Vary, and skip rule 5
2. [OCMLabs] Static assets (base)
(http.host in {"www.example.com"}) and (starts_with(http.request.uri.path, "/static/") or starts_with(http.request.uri.path, "/media/"))- Cache eligibility: Eligible for cache
- Edge TTL: Ignore cache-control header and use this TTL, 1 year (31536000 seconds)
- Browser TTL: Override origin, 1 year (31536000 seconds)
3. [OCMLabs] Bypass protected paths (base)
Same pattern for every bypass path: an eq term for the bare path and a starts_with term for everything under it, on lower(http.request.uri.path). A final group bypasses query strings containing ___store= or ___from_store=, the store switch URLs.
(http.host in {"www.example.com"}) and ((lower(http.request.uri.path) eq "/checkout" or starts_with(lower(http.request.uri.path), "/checkout/") or lower(http.request.uri.path) eq "/customer" or starts_with(lower(http.request.uri.path), "/customer/") or lower(http.request.uri.path) eq "/sales" or starts_with(lower(http.request.uri.path), "/sales/") or lower(http.request.uri.path) eq "/wishlist" or starts_with(lower(http.request.uri.path), "/wishlist/") or lower(http.request.uri.path) eq "/paypal" or starts_with(lower(http.request.uri.path), "/paypal/") or lower(http.request.uri.path) eq "/rest" or starts_with(lower(http.request.uri.path), "/rest/") or lower(http.request.uri.path) eq "/graphql" or starts_with(lower(http.request.uri.path), "/graphql/") or lower(http.request.uri.path) eq "/admin" or starts_with(lower(http.request.uri.path), "/admin/") or lower(http.request.uri.path) eq "/downloadable" or starts_with(lower(http.request.uri.path), "/downloadable/") or lower(http.request.uri.path) eq "/newsletter/subscriber" or starts_with(lower(http.request.uri.path), "/newsletter/subscriber/") or lower(http.request.uri.path) eq "/review/product/post" or starts_with(lower(http.request.uri.path), "/review/product/post/") or lower(http.request.uri.path) eq "/catalogsearch/advanced/result" or starts_with(lower(http.request.uri.path), "/catalogsearch/advanced/result/") or lower(http.request.uri.path) eq "/contact" or starts_with(lower(http.request.uri.path), "/contact/")) or (http.request.uri.query contains "___store=" or http.request.uri.query contains "___from_store="))- Cache eligibility: Bypass cache
4. [OCMLabs] Bypass non-GET (base)
(http.host in {"www.example.com"}) and (http.request.method ne "GET")- Cache eligibility: Bypass cache
5. [OCMLabs] Bypass on vary cookie (base)
Only when Vary Handling is Bypass.
(http.host in {"www.example.com"}) and (http.cookie contains "X-Magento-Vary=") and (not (starts_with(http.request.uri.path, "/static/") or starts_with(http.request.uri.path, "/media/")))- Cache eligibility: Bypass cache
6. [OCMLabs] Bypass query strings (base)
Only when Cache Query Strings is No.
(http.host in {"www.example.com"}) and (http.request.uri.query ne "") and (not (starts_with(http.request.uri.path, "/static/") or starts_with(http.request.uri.path, "/media/")))- Cache eligibility: Bypass cache
Save the rules in this order, top to bottom. The full reference is on the Cache Rules docs page.
Step 4: Verify with the health checks
Run the checks, or click Run checks now on the Health tab:
bin/magento ocmlabs:cloudflare:healthThe Cache rules group confirms a [OCMLabs] Cache storefront HTML rule exists for the website's hosts, the bypass rules exist and sit below it, the X-Magento-Vary cookie is handled by the bypass rule or an Enterprise cache key, a rule bypasses non-GET requests, and the edge TTL matches the module's. That last check warns when a rule overrides the origin TTL. Do not add a "Cache Everything" rule or set an edge TTL override on rule 1: either one makes Cloudflare ignore private, no-store and cache checkout and account pages.
Then check the edge by hand:
curl -sI https://www.example.com/some-category.html | grep -i cf-cache-status
curl -sI https://www.example.com/customer/account/login/ | grep -i cf-cache-statusThe first shows HIT from the second request onward once edge caching is on. The second shows DYNAMIC or BYPASS. All 25 checks, including the live probes behind these two curls, are in how to run Cloudflare health checks for Magento.
The rules alone cache nothing. Rule 1 respects origin headers, so until Enable Edge Caching of HTML is on, the category page stays DYNAMIC. Turning that on and tuning bypass paths, vary and query strings is the next step: how to cache Magento HTML at the Cloudflare edge.
If you would rather have someone check the zone and the rules for you, that is part of our performance and infrastructure work.
✦ FAQ
Why does Cloudflare not cache my Magento pages without a cache rule?+–
Why not just use a Cache Everything rule?+–
What does the dry run show?+–
Will applying the rules touch rules I wrote myself?+–
How do several Magento websites share one Cloudflare zone?+–
Which health checks confirm the rules are right?+–

Shane Blandford
Founder of Orange Collar Media, a Denver ecommerce agency behind 800+ Magento and Shopify builds. In Magento since version 1.x - building, rescuing, and supporting revenue-critical stores since 2008.
✦ KEEP READING
Related from the Journal.
Why put Cloudflare in front of Magento: what a CDN does for a store, what it does not, and what breaks
What Cloudflare does for a Magento store: a CDN for static files, edge-cached HTML, DDoS and bot protection, a WAF, and the five settings that break checkout.

OCM Labs Cloudflare: free edge caching for Magento, on Magento's own terms
A free, open-source Magento module that caches storefront HTML at the Cloudflare edge using Magento's own full page cache rules, and purges by cache tag.

How to use Cloudflare development mode and analytics from the Magento admin
Turn Cloudflare development mode on before a theme deploy, run a quick purge and read Cloudflare analytics from the Magento admin with a free module.
