I Added a CDN Cache to My Site and It Got Slower. Here's the Math I Should Have Done First. — Opportunihub
Course Remote

I Added a CDN Cache to My Site and It Got Slower. Here's the Math I Should Have Done First.

Javeed Shaik · Remote

At a glance

Type
Course
Organisation
Javeed Shaik
Location
Remote
Work mode
Remote
Deadline
Rolling / not stated
Posted
27 Aug 2026

About this course

<p>Last week I put a CDN cache in front of a static site, expecting it to get faster.</p> <p>But instead, it got measurably slower. Not subtly: an independent crawler that had flagged 38 slow pages before the change flagged <strong>75</strong> after it.</p> <p>I reverted it the same day. This is what happened, why it happened, and the one calculation that would have told me not to bother before I deployed anything.</p> <h2 id="heading-table-of-contents">Table of Contents</h2> <ul> <li><p><a href="#heading-prerequisites">Prerequisites</a></p> </li> <li><p><a href="#heading-the-setup">The Setup</a></p> </li> <li><p><a href="#heading-what-i-changed">What I Changed</a></p> </li> <li><p><a href="#heading-the-result">The Result</a></p> </li> <li><p><a href="#heading-why-it-backfired-part-one-a-miss-is-not-free">Why it Backfired, Part One: a MISS is Not Free</a></p> </li> <li><p><a href="#heading-why-it-backfired-part-two-crawlers-are-always-cold">Why it Backfired, Part Two: Crawlers Are Always Cold</a></p> </li> <li><p><a href="#heading-the-calculation-i-shouldve-done-first">The Calculation I Should've Done First</a></p> </li> <li><p><a href="#heading-the-part-that-stings">The Part That Stings</a></p> </li> <li><p><a href="#heading-a-technique-worth-keeping">A Technique Worth Keeping</a></p> </li> <li><p><a href="#heading-what-id-tell-you-to-do-instead">What I'd Tell You to Do Instead</a></p> </li> </ul> <h2 id="heading-prerequisites">Prerequisites</h2> <p>You don't need to have run a CDN before. But this will make more sense if you're comfortable with:</p> <ul> <li><p><strong>What a CDN does at a high level:</strong> it keeps copies of your pages on servers around the world and serves each visitor from a nearby one.</p> </li> <li><p><strong>Basic HTTP caching headers:</strong> roughly what <code>Cache-Control</code> and <code>max-age</code> are for. I explain <code>s-maxage</code> and <code>must-revalidate</code> where they come up.</p> </li> <li><p><strong>Reading a</strong> <code>curl</code> <strong>command:</strong> every measurement in this article is a one-line <code>curl</code> you can run against your own site.</p> </li> </ul> <p>No Cloudflare-specific knowledge is assumed, and there's nothing to install. The core lesson is arithmetic, and it applies to any CDN.</p> <h2 id="heading-the-setup">The Setup</h2> <p>The site is a static Astro build: 77 HTML pages, no server-side rendering, and no database. It sits behind Cloudflare on the free plan, with an origin server in Navi Mumbai. Traffic is modest: roughly 9 visitors a day.</p> <p>Google Search Console reported an <strong>average response time of 711 ms</strong>. Google's own guidance is 200 ms. That's 3.5× over, and it looked like an obvious problem with an obvious cause.</p> <p>The cause was real: Cloudflare was caching <strong>none</strong> of the HTML:</p> <pre><code class="language-plaintext">$ curl -sI https://example.com/ | grep -i 'cache-control|cf-cache-status' cache-control: no-cache cf-cache-status: DYNAMIC </code></pre> <p><code>DYNAMIC</code> means Cloudflare isn't caching the response at all. Every single HTML request (from every visitor and every crawler on earth) was traveling all the way to Mumbai.</p> <p>The origin was sending <code>Cache-Control: no-cache</code>, which was a deliberate choice by past-me so that deploys would be visible immediately. Static assets (JS, CSS, fonts, and images) were cached fine. Only the HTML was passing through.</p> <p>So: origin far away, HTML uncached, and a metric saying responses were slow. Cache the HTML at the edge and the problem goes away. Right?</p> <h2 id="heading-what-i-changed">What I Changed</h2> <p>I changed two things, in this order.</p> <p><strong>1. The origin header.</strong> From <code>no-cache</code> to:</p> <pre><code class="language-plaintext">Cache-Control: public, max-age=0, s-maxage=31536000, must-revalidate </code></pre> <p>This is a useful pattern worth knowing. <code>max-age=0, must-revalidate</code> means <strong>browsers</strong> revalidate on every request, so a deploy is instantly visible to users, exactly what <code>no-cache</code> guaranteed. But <code>s-maxage</code> applies <strong>only to shared caches</strong>, which lets a CDN hold the object for a year while browsers keep checking.</p> <p><strong>2. A Cloudflare Cache Rule.</strong> Here's a detail that surprised me: the header alone does nothing. Cloudflare won't cache extensionless HTML on the strength of your <code>Cache-Control</code> header. I verified this on a throwaway path rather than assuming it:</p> <pre><code class="language-plaintext">req 1: cf-cache-status: DYNAMIC req 2: cf-cache-status: DYNAMIC req 3: cf-cache-status: DYNAMIC </code></pre> <p>Five requests, with <code>s-maxage</code> set to a year, still <code>DYNAMIC</code> every time. You need an explicit Cache Rule marking the response <em>eligible for cache</em>. That's actually a useful property. It means you can ship the header change safely, well ahead of switching caching on.</p> <p>With the rule deployed, it worked exactly as intended:</p> <pre><code class="language-plaintext">req 1: cf-cache-status: MISS req 2: cf-cache-status: HIT req 3: cf-cache-status: HIT </code></pre> <p>And it looked like a win. Time to first byte on a warm page dropped from ~0.28 s to ~0.17 s.</p> <p>I was measuring from India. The origin is in India. <strong>Hold that thought.</strong></p> <h2 id="heading-the-result">The Result</h2> <p>The next crawl came back worse. Same site, same day, and the same 80 URLs:</p> <table> <thead> <tr> <th>Crawl</th> <th>HTML caching</th> <th>Slow pages flagged</th> </tr> </thead> <tbody><tr> <td>11:58 AM</td> <td>off</td> <td><strong>38</strong></td> </tr> <tr> <td>6:04 PM</td> <td>on</td> <td><strong>75</strong></td> </tr> </tbody></table> <p>Nearly double. I had made the exact metric I was trying to fix substantially worse.</p> <h2 id="heading-why-it-backfired-part-one-a-miss-is-not-free">Why it Backfired, Part One: a MISS is Not Free</h2> <p>The mental model I had was that caching is a coin flip between two outcomes: a HIT, which is fast, and a MISS, which costs the same as having no cache at all.</p> <p>That second half is wrong. On a MISS, the CDN doesn't just proxy your response through. It has to <strong>store</strong> the object as it streams. That work costs something.</p> <p>I measured it by purging the cache and then fetching the same pages two ways: through Cloudflare, and straight to the origin IP with <code>--resolve</code>.</p> <pre><code class="language-bash"># through Cloudflare, cache cold curl -s -o /dev/null -w '%{time_starttransfer}' https://example.com/page # straight to origin, bypassing Cloudflare entirely curl -sk -o /dev/null -w '%{time_starttransfer}' --resolve example.com:443:203.0.113.10 https://example.com/page </code></pre> <p>Across six pages:</p> <table> <thead> <tr> <th>path</th> <th>TTFB</th> </tr> </thead> <tbody><tr> <td>warm HIT</td> <td><strong>0.239 s</strong></td> </tr> <tr> <td><strong>cold MISS</strong></td> <td><strong>0.366 s</strong></td> </tr> <tr> <td>straight to origin (no caching)</td> <td><strong>0.281 s</strong></td> </tr> </tbody></table> <p>A cache MISS was <strong>~85 ms slower</strong> than simply not caching. Which means every request that misses is now <em>worse off</em> than it was before I started.</p> <h2 id="heading-why-it-backfired-part-two-crawlers-are-always-cold">Why it Backfired, Part Two: Crawlers Are Always Cold</h2> <p>A cache only pays off when the same URL is requested again while it's still cached, at the same edge location.</p> <p>A crawler doesn't do that. It fetches each URL <strong>once</strong>.</p> <p>I could verify this precisely, and the technique is worth stealing: <strong>if a request is served from the CDN's cache, it never reaches your origin.</strong> So the origin access log is a direct measurement of your miss rate.</p> <pre><code class="language-bash">grep -ic "crawler-user-agent" /var/log/nginx/access.log </code></pre> <p>During the crawl of <del>80 URLs, my origin logged **</del>82 requests**. Every single page the crawler asked for was a miss. A <strong>0% hit rate</strong>, and every one of those misses now carried the extra ~85 ms.</p> <p>The same logic applies to first-time human visitors, who are also, by definition, arriving cold.</p> <h2 id="heading-the-calculation-i-shouldve-done-first">The Calculation I Should've Done First</h2> <p>Here's the whole thing, and it takes about a minute.</p> <p>You have three numbers:</p> <ul> <li><p><code>H</code>: time on a cache hit</p> </li> <li><p><code>M</code>: time on a cache miss</p> </li> <li><p><code>B</code>: your baseline, the time with no caching at all</p> </li> </ul> <p>Caching only wins when your average request beats the baseline:</p> <pre><code class="language-plaintext">h × H + (1 − h) × M &lt; B </code></pre> <p>Solve for the hit rate <code>h</code>:</p> <pre><code class="language-plaintext">h &gt; (M − B) / (M − H) </code></pre> <p>For my numbers:</p> <pre><code class="language-plaintext">h &gt; (0.366 − 0.281) / (0.366 − 0.239) h &gt; 0.085 / 0.127 h &gt; 0.67 </code></pre> <p><strong>I needed a 67% cache hit rate just to break even.</strong></p> <p>Now the reality check. 77 pages, and about 9 visitors a day, plus a search crawler refetching each page every few days. Call it 35 HTML requests a day, spread across 77 URLs <em>and</em> across many edge locations worldwide. And a full cache purge on every deploy.</p> <p>The realistic hit rate is close to zero. I needed 67%.</p> <p>The change was never going to work, and I could have known that before writing a line of config.</p> <h2 id="heading-the-part-that-stings">The Part That Stings</h2> <p>The diagnosis was correct. The origin genuinely is far from most of the traffic. The HTML genuinely wasn't cached. The 711 ms was real.</p> <p>I just picked a fix without asking <strong>what fraction of requests would actually benefit from it</strong>.</p> <p>And my verification made it worse, because I measured from a laptop sitting in the same country as the origin. Local <code>curl</code> timings said the change was a success. Only the external crawler – the thing that raised the issue in the first place – showed the regression.</p> <p>So just make sure you <strong>verify against the metric that flagged the problem, not a proxy for it.</strong></p> <h2 id="heading-a-technique-worth-keeping">A Technique Worth Keeping</h2> <p>One piece of this survived the revert, and it's genuinely useful.</p> <p>If you cache HTML at the edge, your deploy pipeline must purge that cache. And <strong>an API call returning</strong> <code>"success": true</code> <strong>isn't evidence the cache actually dropped anything.</strong> So don't trust it. Check.</p> <pre><code class="language-bash">LOCAL=$(shasum -a 256 dist/index.html | cut -d' ' -f1) LIVE=$(curl -s https://example.com/ | shasum -a 256 | cut -d' ' -f1) if [ "$LOCAL" != "$LIVE" ]; then echo "EDGE IS STALE — this deploy is not live" &gt;&amp;2 exit 3 fi </code></pre> <p>That compares the bytes your CDN is actually serving against the bytes you just built. It's the difference between "the purge API said OK" and "the site is genuinely updated."</p> <p>A related trap: if those hashes <em>never</em> match, suspect a feature that rewrites HTML at the edge (script optimizers, email obfuscation, auto-minification) before you suspect the cache.</p> <p>Better still, don't hardcode the assumption that caching is on. Ask:</p> <pre><code class="language-bash">STATE=$(curl -sI https://example.com/ | tr -d '\r' | awk 'tolower($1)=="cf-cache-status:"{print $2}') case "$STATE" in DYNAMIC|BYPASS) echo "HTML isn't cached; a missing purge is harmless" ;; *) echo "HTML IS cached — a failed purge means this deploy is invisible" ;; esac </code></pre> <p>Now the check corrects itself when someone toggles the cache rule, instead of quietly rotting.</p> <h2 id="heading-what-id-tell-you-to-do-instead">What I'd Tell You to Do Instead</h2> <p>Calculate your break-even hit rate before you deploy. <code>(M − B) / (M − H)</code>. If you can't plausibly reach it, stop.</p> <p>Estimate your real hit rate honestly. Requests per day, divided across your URLs, divided again across edge locations, reset on every deploy. It's usually far lower than it feels.</p> <p>Measure from where your users and crawlers actually are, not from the machine next to your origin.</p> <p>Remember caching is a popularity bet. It rewards sites where the same URLs are requested repeatedly, in a short window. A high-traffic site would have won here comfortably. A 9-visitors-a-day site never could.</p> <p>And if you're staring at a slow origin far from your audience, the honest answer might not be a cache at all. It might be moving the origin.</p> <p><em>I write about the engineering behind</em> <a href="https://healthycalculatorhub.com"><em>Healthy Calculator Hub</em></a><em>, a set of free health and fitness calculators — including, evidently, the optimizations that don't work.</em></p>

How to apply

  1. 1 Read the full details above and confirm you meet the eligibility criteria.
  2. 2 Prepare your documents — an updated CV, and any cover letter, proposal or certificates required.
  3. 3 Click Apply on official site to complete your application on Javeed Shaik’s official page.
  4. 4 Submit as early as possible — many close once filled.
Apply on official site

Sourced from freecodecamp. Always verify details on the official website. Opportunihub never charges you to apply.

Frequently asked questions

How do I apply for I Added a CDN Cache to My Site and It Got Slower. Here's the Math I Should Have Done First.?

Review the full details and eligibility on this page, prepare your documents, then use the “Apply on official site” button to complete your application on Javeed Shaik’s official page.

Is this opportunity remote or location-based?

This opportunity is remote-friendly and open to applicants who can work from anywhere.

Is I Added a CDN Cache to My Site and It Got Slower. Here's the Math I Should Have Done First. free to apply for?

Opportunihub lists this Course for free. Legitimate Courses do not ask for payment to apply — never pay a fee to submit an application.