11 min read

Cloudflare Advanced - The Layered Cache Strategy (2026)

Digitized picture of a rusty satellite spray-painted with the Cloudflare logo in Earth orbit.
Taking CloudFlare to the Moon & Back!Taking CloudFlare to the Moon & Back!

In Part 1, we secured your DNS. In Part 2, we enabled all the awesome free Cloudflare free security security features. Now, in Part 3, we unlock the real power of the Edge: Intelligent Caching.

This is the third post in the Cloudflare series, showcasing utilizing your domain with their free tier. if you missed the first two posts, click back with the series navigator below.


Most guides tell you to "Cache Everything" and hope for the best. That breaks your site for logged-in members. Others tell you to create complex bypass rules first.

If you are self-hosting a Ghost blog (or any CMS/website), your server is in one physical location (e.g., your basement/rack/IKEA Lack table!). When a user in London visits, they have to wait for light to travel across the Atlantic ocean, which, is big! Thankfully fibre is quite fast, but there is a delay, and when your site gets busier there becomes contention for that data.

We are going to use a Layered Strategy. We set a "base layer" of caching for the whole site, and then we layer specific "overrides" on top of it for members and static files. This configuration is currently running on Core Lab, keeping the site instant for guests while ensuring members never see stale data. I may have to revisit this logic if the site grows much larger, but when we cross that bridge... One can hope! ;)

We can cheat physics using Cloudflareโ€™s Edge Cache.

The goal of this guide is to make your dynamic content feel like a static site and react that quickly. We will force Cloudflare to cache everything (including the HTML pages that it normally does not) and then use a Cloudflare Worker to automatically clear that cache the instant you publish a post!

As I always say, a picture speaks a thousand words:
flowchart TD
    %% ===========================
    %% CLOUDFLARE LAYERED CACHE STRATEGY
    %% ===========================

    subgraph Base["๐ŸŒ Rule #1 โ€” Base Layer
Cache Everything (HTML) for 7 Days"] R1["๐ŸŸฆ 7-Day Cached HTML
โ€ข Speeds up guest traffic
โ€ข Default cache state for whole site"] end subgraph Override["๐Ÿ›‘ Rule #2 โ€” Override
Bypass Cache for Members & Admin"] R2["๐Ÿ”ด Cache Bypass
โ€ข Logged-in users
โ€ข Admin dashboard
โ€ข Dynamic pages (cart/checkout/etc)"] end subgraph Boost["๐Ÿš€ Rule #3 โ€” Static Asset Boost
Cache for 1 Month"] R3["๐ŸŸจ 30-Day Cache
โ€ข Images
โ€ข CSS/JS
โ€ข Fonts (woff2)
โ€ข Media assets"] end R1 --> R2 --> R3 style Base fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#034168 style Override fill:#fee2e2,stroke:#dc2626,stroke-width:2px,color:#7f1d1d style Boost fill:#fef9c3,stroke:#ca8a04,stroke-width:2px,color:#7c5800 style R1 fill:#fff,stroke:#0284c7,stroke-width:2px style R2 fill:#fff,stroke:#dc2626,stroke-width:2px style R3 fill:#fff,stroke:#ca8a04,stroke-width:2px

Prerequisites:

  • A Cloudflare account (Free Plan).
  • A Ghost blog / website / something online (Self-hosted).
  • Access to your Cloudflare Dashboard and Admin panel.
    • For this example, I'll be showing how it's done for my blog here which is based on Ghost but the concepts should be the same for other sites.

๐Ÿง  The Concept: Static vs. Dynamic Caching

Before we click buttons, you need to understand the strategy.

  1. Static Content (Images, CSS, JS): Cloudflare caches these by default. You don't need to do anything.
  2. Dynamic Content (HTML): By default, Cloudflare does NOT cache the actual HTML pages of your blog. It fetches them from your server every single time. Not what you expected eh? Me neither!
The Strategy: We are going to force Cloudflare to cache the HTML too. This reduces the load on your server to near-zero and makes your site load instantly worldwide.

โš ๏ธ The Warning (Ghost Members):

If you use the "Members/Login" feature of Ghost, aggressive HTML caching can break the "Logged in as..." functionality. I will show you a "Pro Tip" in Step 2 to handle this using modern Cache Rules.


๐Ÿ› ๏ธ Part 1: Setting Up Edge Caching (The Modern Way)

We are going to use Cache Rules, which are the modern, more powerful replacement for the old "Page Rules."

The Core Lab Strategy: "Last Match Wins"

We will configure 3 Cache Rules in specific order. Cloudflare processes these top-to-bottom, meaning the last rule that matches is the one that applies.

  1. ๐ŸŒ Rule #1 (The Base): Cache Everything for 7 Days. (This sets the default state).
  2. ๐Ÿ›‘ Rule #2 (The Override): Bypass Cache for Members & Admins. (This overwrites Rule #1 for logged-in users).
  3. ๐Ÿš€ Rule #3 (The Boost): Cache Static Assets for 1 Month. (This overwrites Rule #1 for images/css, giving them an even longer life).

Navigate to your Domain->Rules->Cache Rules in your Cloudflare Dashboard.

Screenshot of my 3 Cloudflare Cache rules, live, as they are today.
My 3 Cloudflare Cache rules, live, as they are today.

Create these rules in this exact order, the order absolutely matters.

Rule #1: The Base Layer (7 Days HTML)

First, we cast a wide net. We tell Cloudflare: "Unless I tell you otherwise later, cache everything on this domain for a week."

  • Rule Name: Cache Public Content (7 Days)
  • For If incoming requests match...
    • Chose Custom filter expression
  • Expression:
    • Hostname equals corelab.tech (Swap with YOUR domain of course)
  • Cache Status: Eligible for cache
  • Edge Cache TTL: Ignore cache-control header -> 7 Days
  • Browser TTL (optional)
    • I set mine to Override origin and use this TTL and set that to 4 hours.
The Effect: Right now, everyone (including you) sees a cached version of the site. This makes it fast, but we need to fix the "logged in" experience next.
Screenshot showing CF 7 day cache rule settings
CF 7 day cache rule settings

Rule #2: The Bypass (Members, Admin & SEO)

Now, we apply the critical overrides. We need to tell Cloudflare to stop caching immediately if a user is logged in (dynamic data) or if a search engine is looking for your site structure. This one will take a beat longer than the first one.

Rule Name: Bypass Cache for MbrsAdmins (or whatever makes sense to you)

๐Ÿ“ก
I have updated this rule & these instructions on May 1 2026. If you previously implemented this rule, have a 2nd look and re-work your rules if things aren't working!
๐Ÿ˜ฎ
Very easy to mess this rule up, pay close attention to the order and where the AND and OR logic chains are! Take a 3rd look at the pic ๐Ÿ˜‰
Screenshot showing the complex rule for members & admins bypassing cache, but it's complex. Use the expression builder below.
This is why using the expression builder is easier and faster than manually clicking through all of this!

So there's 2 of those And sets of rules, then the rest have Or in between them.

Expression code block which you can copy & paste into the Expression builder:

(http.host eq "YOURDOMAIN.COM" and http.cookie contains "ghost-members-ssr") or (http.host eq "YOURDOMAIN.COM" and http.cookie contains "ghost-admin-api-session") or (http.request.uri contains "/ghost/") or (http.request.uri contains "/p/") or (http.request.uri contains "/member/") or (http.request.uri.path contains "sitemap") or (http.request.uri.path contains ".xsl") or (starts_with(http.request.uri.path, "/.ghost/activitypub/"))

Once you paste this in and click to Use Expression Builder the rules above are converted to a more easily modifiable human format as the picture shows.

Cache Status: Bypass cache

The Logic: Because this rule comes after Rule #1 (the "Cache Everything" rule), rule #1 takes precedence first.

The Effects:

For Users: If Cloudflare detects a "Login Cookie," it discards the cache and fetches live data so your members never see a generic cached page.
For Google: By adding sitemap and .xsl here, we ensure that every time you publish a post, Googlebot sees the new link instantly - no waiting 7 days for the cache to clear.

Rule #3: The "Secret Sauce" (Static Assets)

Finally, we optimize the heavy files. Rule #1 set images to 7 days, but images rarely change. Let's override that and force them to cache for a full month.

๐Ÿ“ก
If you change images, or update them, you'll have to flush your cache in the Cloudflare console for the new images to show up.
  • Rule Name: Cache - Static Assets (1 Month)
  • Expression Code Block (Don't forget to customize it to your domain!):
(http.host eq "YOURDOMAIN.COM" and http.request.uri.path contains "/content/") or (http.host eq "YOURDOMAIN.COM" and http.request.uri.path contains "assets.corelab.tech/assets/") or (http.host eq "YOURDOMAIN.COM" and http.request.uri.path contains "assets.corelab.tech/public/")
  • Cache Status: Eligible for cache
  • Edge Cache TTL: Ignore cache-control header -> 1 Month
  • Browser TTL: Override origin -> 1 Month
The Result: Even if a user is logged in (Rule #2), this Rule #3 also matches for their images. It ensures that everyone, member or guest, gets lightning-fast images from the cache, while only the HTML is bypassed for members.
Screenshot of Third Cloudflare rule which caches all static assets for 1 month otherwise.
Third Cloudflare rule which caches all static assets for 1 month otherwise.

๐Ÿ•ต๏ธ Verification: How to Test

It is critical to verify that your "layering" is working.

1. Test as a Guest (Incognito Window): Visit your homepage. Check the Network tab (F12) for the main document request.

  • Header: cf-cache-status: HIT (or MISS then HIT on refresh)
  • Explanation: You matched Rule #1.

2. Test as a Member (Logged In): Log in to your site. Check the same request.

  • Header: cf-cache-status: BYPASS
  • Explanation: You matched Rule #1, but then you matched Rule #2, which overwrote it to "Bypass."

3. Test an Image: Right-click an image and open it in a new tab. Check the headers.

  • Header: cache-control: max-age=2592000 (30 Days)
  • Explanation: You matched Rule #1 (7 days), but then matched Rule #3, which upgraded it to 1 Month.

โš™๏ธ Part 2: The Automation (Cloudflare Workers)

If you stopped now, your blog would be fast, but stale. New posts wouldn't appear for a month! You could simply do a full purge every time you post, but that is just another thing you have to do... In 2026, we automate. We need a robot to tell Cloudflare: "I just published! Clear the cache!"

We will use a Cloudflare Worker (Free) triggered by a Ghost Webhook.

Step 1: Create a Cloudflare API Token

The Worker needs permission to purge your cache.

  1. Go to My Profile > API Tokens.
  2. Click Create Token.
  3. Use the "Custom Token" template.
  4. Permissions:
    • Zone -> Cache Purge -> Purge
  5. Zone Resources:
    • Include -> Specific zone -> corelab.tech (you'd use YOUR domain here)
  6. Create the token and COPY IT. You will not see it again.

Step 2: Create the Worker (Crazy this is free!)

  1. Go to Compute & AI -> Workers tab in the sidebar.
  2. Click Create Service.
  3. Name it: ghost-purge or autopurger. Select "HTTP handler" (standard).
  4. Click Create service.
  5. Click Edit code.
  6. Delete the existing code and paste this script. This script listens for the Ghost webhook and commands Cloudflare to purge the specific URL that was updated.
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const url = new URL(request.url);
  const { pathname, searchParams } = url;
  
  if (pathname === '/purge-full-cache') {
    const zoneId = searchParams.get('zone');
    
    if (!zoneId) {
      return new Response('Missing zone ID. Please provide a zone ID in the query parameter.', { status: 400 });
    }
    
    const apiKey = 'YOUR_API_KEY';
    const email = 'YOUR_CLOUDFLARE_LOGIN';
    
    const purgeResponse = await fetch(`https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache/`, {
      method: 'POST',
      headers: {
        'X-Auth-Email': email,
        'X-Auth-Key': apiKey,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ purge_everything: true }),
    });
    
    if (purgeResponse.ok) {
      return new Response(`Full cache purge initiated successfully for zone ${zoneId}.`);
    } else {
      const errorData = await purgeResponse.json();
      return new Response(`Failed to initiate full cache purge: ${JSON.stringify(errorData)}`, { status: 500 });
    }
  }
  
  return new Response('Not Found', { status: 404 });
}

Fairly straight forward.

๐Ÿชƒ
In the future I'll update this to show how to use a variable in the code above vs hardcoding the API key and such, it's safer & follows best practice, however even the worker call from Ghost to CloudFlare is fully encrypted, so not to worry really. Only if something man-in-the-middle attacks your service and CloudFlare!

๐Ÿ”— Part 3: Connecting Ghost

The final step is telling Ghost to talk to your Worker.

  1. Log in to your Ghost Admin.
  2. Go to Settings (Gear) > Integrations.
  3. Click Add custom integration (bottom of page).
  4. Name it "Cloudflare Purge".
  5. In the Webhooks section, click Add webhook.
    1. There's two methodologies you can go with here, one webhook, or two separate. I chose simplest, using one.
  6. Option A - Create one webhook:
    1. Event: Site changed (rebuild) | Target URL: Your Worker URL.
      1. This means that if ANY change is made to any post on the site, the entire cache on CloudFlare is wiped and CloudFlare then has to re-cache & crawl the site. "Nuke from orbit".
  7. Option B - Create two webhooks:
    • Event: Post published | Target URL: Your Worker URL.
    • Event: Post updated | Target URL: Your Worker URL.
      • This is more granular and keeps a good chunk of your static content still cached.
  8. Click Save.

๐Ÿš€ The Result & Cache Score

  1. You publish a post.
  2. Ghost fires a signal to your Cloudflare Worker.
  3. The Worker tells Cloudflare, "Clear the cache for this specific URL."
  4. Global Cache: Your readers serve the super-fast cached version (HIT) from the edge.
  5. Zero Staleness: The moment you fix a typo, the cache clears instantly.

When done, after about a week (depending how busy your site is!) you should see some incredible statistics like this -

Cloudflare Dashboard showing very close to 90% cache hit status and 90% cached data served!
Cloudflare Dashboard showing very close to 90% cache hit status and 90% cached data served!

You now have the best of both worlds: the dynamic power of Ghost and the static speed of the Cloudflare Edge, all for $0/month.


This is a part of my practical cybersecurity roadmap for homelabs/self-hosters, hop over there to begin your next adventure!

A Practical Cybersecurity Roadmap for Homelabs
Learn to protect your data, services and privacy with actionable steps and clear tutorials. So, youโ€™ve built an incredible homelab. Youโ€™re spinning up services in Docker, managing your media, and maybe even self-hosting your own website. You are the master of your own data. But with every new service you

If you are enjoying and getting use out of this post or the site, feel free to sign up or donate, this would be hugely appreciated by me and signals to me you value the content and want more!๐Ÿ‘‡

Core Lab
Core Lab: Building Your Digital Fortress. Explore homelabbing, smart homes & secure self-hosting. Join our community and build your homelab today!