How to use Cloudflare with Varnish for Magento
Stock Magento VCL tells Cloudflare not to cache HTML. Export a Cloudflare-aware VCL from Magento, syntax-check it, load it and verify the headers arrive.

Put Cloudflare in front of a Magento store that already runs Varnish and you get cf-cache-status: DYNAMIC on every page, forever. Nothing is wrong on the Cloudflare side. The stock Magento Varnish configuration is doing what it was written to do, and that defeats any cache in front of it.
Here is why, what OCM Labs Cloudflare (free and open source) changes when it detects Varnish, how to export and load the Cloudflare-aware VCL, and how to prove the headers survive the trip. If edge caching is not on yet, read how to cache Magento HTML at the Cloudflare edge first; this post assumes those settings are in place.
Why stock Magento VCL blocks the edge
Magento's generated VCL does two things in vcl_deliver that matter here:
- It rewrites
Cache-Controltono-cacheon every response that leaves Varnish. - It removes the tag header before the response goes out.
Both make sense when Varnish is the last cache before the browser. But Cloudflare reads the same response. It sees no-cache and no Cache-Tag, and stores nothing. HTML is served by Varnish only, and Cloudflare adds latency without adding a cache.
The fix is not a Cloudflare rule that forces caching; that would also cache whatever Varnish marked private. The fix is a VCL that lets the right responses through with the right headers, which is what the module exports.
What changes in Varnish mode
The module reads Magento's caching application setting at Stores > Configuration > Advanced > System > Full Page Cache. When it is set to Varnish, the module changes how it works on every response:
| BUILT-IN FPC MODE | VARNISH MODE | |
|---|---|---|
| CACHE-CONTROL REWRITE IN PHP | Yes | No, left to Varnish |
| SESSION COOKIE STRIPPING IN PHP | Yes | No, left to Varnish |
| EDGE MARKER (INTERNAL TTL HEADER) ADDED | Yes | Yes |
| CACHE-TAG HEADER ADDED | Yes | Yes |
| WHO MAKES THE EDGE DECISION | Magento | The VCL |
Magento's own headers and cookies are left to Varnish, because Varnish already rewrites Cache-Control and strips session cookies. The module still adds its edge marker and the Cache-Tag header to responses Magento considers public, so the VCL can see them and decide what reaches Cloudflare.
Two limits apply in Varnish mode:
- Edge caching covers default-context pages only. Visitors on another store view, currency or customer group carry the
X-Magento-Varycookie and are served by Varnish, not the edge. - Vary Handling must stay at Bypass. The
Cache keyoption is not supported behind Varnish.
Step 1: Export the VCL
Run the export from the Magento root, naming the Varnish version you run and where to write the file:
bin/magento ocmlabs:cloudflare:vcl:export --varnish-version=6 --output=/tmp/default.vcl--varnish-version accepts 4, 5, 6 or 7; 6 is the default. --output (short form -o) writes to a file; leave it off and the VCL goes to standard output, handy for a diff against your current file. The command exits 1 on any error.
From the admin, the Download Cloudflare VCL button on the Health tab produces the same file.
What you get is Magento's own generated VCL for that version, with two additions and nothing else changed.
Step 2: Syntax-check it
Before the file goes anywhere near a running Varnish, compile it:
varnishd -C -f /tmp/default.vcl > /dev/nullvarnishd -C compiles the VCL and prints the result; sending that to /dev/null leaves only the errors, if any. A clean exit means the file parses for the Varnish version on that box. A mismatch between --varnish-version and the installed varnishd shows up here, not during a reload.
Step 3: Load it
Loading is the same as any VCL change on your setup: put the exported file where your Varnish reads its configuration, then reload the service or use varnishadm to load and switch to it. Follow the procedure you already use for Magento VCL changes. The exported file replaces the stock one; it is not a patch on top of it.
What the two additions do
In vcl_recv, a note is made of whether the request carries the X-Magento-Vary cookie. Nothing else happens there; the note is read later.
In vcl_deliver, a response that carries the module's edge marker gets Cache-Control: public, max-age=0, s-maxage=<ttl> instead of Magento's no-cache rewrite, with the TTL taken from the marker. Cache-Tag is left in place for Cloudflare. The marker itself is removed before the response leaves Varnish, so visitors never see it.
The marker branch is guarded. It skips:
- any response that is already private or
no-store - anything Varnish itself marked uncacheable
- any request that carried the vary cookie, per the note from
vcl_recv
The rule behind the guards: a page Varnish would not cache is never made cacheable at the edge. Only pages Varnish stored, and Magento marked public, get the edge headers.
Varnish keeps old objects
Varnish holds on to objects it stored before a configuration change until they expire or are purged. Pages already in Varnish still carry the headers they were stored with. The same applies after editing Bypass Paths or turning edge caching off. So after any of those changes, purge Varnish as well as Cloudflare:
bin/magento cache:clean full_pageWith Purge Everything on Full Page Cache Clean turned on, that one command clears both. How the purge side works, including the queue and the purge log, is in how to purge Cloudflare cache from Magento.
Step 4: Verify from Magento
The "Origin sends edge cache headers" health check fetches a page straight from the address in Storefront Origin and reports whether Cache-Control and Cache-Tag arrive intact. For this check to tell you anything about Varnish, set Storefront Origin to the Varnish address, not the web server behind it. Run it from the Health tab or from the shell:
bin/magento ocmlabs:cloudflare:healthA pass means the exported VCL is loaded and passing the headers through. A fail after you loaded the VCL means something else between Varnish and Cloudflare is still stripping them: a second proxy, a load balancer, or a web server rule. The other 24 checks and what to do when they fail are covered in how to run Cloudflare health checks for Magento.
Step 5: Verify with curl
For a second opinion, ask Varnish directly, bypassing Cloudflare:
curl -sI -H "Host: www.example.com" http://varnish-host/some-category.html | grep -iE "cache-control|cache-tag"You should see Cache-Control: public, max-age=0, s-maxage=... and a Cache-Tag line. If you still see no-cache, the old VCL is still active, or the guards excluded the page; try a plain category page with no X-Magento-Vary cookie. Once Varnish is right, request the page through Cloudflare twice and look for cf-cache-status: HIT on the second request. Cloudflare strips Cache-Tag from what it sends to visitors, so its absence on the public URL is expected.
If you would rather leave the VCL alone
Changing VCL on a production box is not always your call. Leave Enable Edge Caching of HTML off and skip this whole page. Purging, the cache rules, the health checks and analytics all keep working; only HTML stays on Varnish instead of the edge. Come back to the export when the VCL change is approved.
The full reference for this feature, including the exact options and exit codes, is on the Varnish docs page.
If you want someone to review your Varnish and Cloudflare layout before you touch production, that is what our performance and infrastructure work covers.
✦ FAQ
Why does Cloudflare show DYNAMIC on every page when Varnish is in front of Magento?+–
Does the module detect Varnish on its own?+–
Which Varnish versions does the export support?+–
Can I use Vary Handling Cache key with Varnish?+–
Why are old pages still served after I loaded the new VCL?+–
Do I have to change the VCL to use the module with Varnish?+–

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.
