My initial goal was to write a post comparing two major hosting offerings for a static tech blog at zero cost. Turns out, there’s an abundance of «Github Pages vs Cloudflare Pages» posts on the web. So the premise shifted to why do I pick Cloudflare Pages.

Google Trends comparing Cloudflare Pages with Github Pages
Google Trends comparing Cloudflare Pages with Github Pages

According to Google Trends graph, Github Pages ranks 77 against 5 points of interest for Cloudflare Pages. Couple of reasons for this are:

  • Github Pages as a platform was announced in 2008, Cloudflare was founded in 20091.
  • Cloudflare announced general availability for it’s Pages in the middle of April 20212.
  • Simplicity — turning a repo into Github Pages takes a couple of clicks.

Yet, in a short period of time, Cloudflare Pages proved to be a highly competitive and solid solution vastly for its integration with other features the company has to offer.

Always Online

If checked with Github Incident History3 to count at least five incidents related to Github Pages in the last year, while Cloudflare Pages4 had three for the same period. Cloudflare offers at least two options to mitigate the possible availability issue. One of which is Always Online which takes snapshots for Wayback Machine. In case segments of Cloudflare responsible for Pages, experience technical issues, Always Online will save the day.

Always Online is available under Configuration section in Caching menu of a site area.

Cache Everything and Edge Cache TTL

Static assets served with Cloudflare Pages are not cached by default. To check the resource status you’ll have to look at the CF-Cache-Status response header.

~ ❯❯❯ curl -I https://gdmka.me | grep -i "CF-Cache-Status"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
cf-cache-status: DYNAMIC

DYNAMIC cache response does not consider the asset to be eligible for cache5 so the page was requested from the Pages service. To benefit from caching I added Cache Level and Edge Cache TTL settings in Page Rules.

Cache Everything with * match pattern instructs Cloudflare to cache all the static assets as well as the dynamic parts, so make sure to set Bypass to any pages with forms.

Edge Cache TTL is basically a setting that controls the period of time before edge servers invalidate the cache and request a new copy from the upstream. With this option on, Cloudflare will overwrite all of the headers sent by the upstream.

I set it to a week because it’s a reasonable interval between new blog entries for me. Plus, a new page build triggers cache invalidation avoiding the problem of stale pages getting served. Now, if Pages encounters any availability issues, the blog will be served from the edge cache (assuming it wasn’t invalidated) hence the second mitigation option.

I ran a performance test to check how content delivery got improved and it’s pretty impressive. According to GTMetrix, Full Load Time for a cached page is 341ms compared to 760ms with default cache settings and Time to Interactive of 273ms against 489ms.

Non-cached

Cached

Redirects

Sometimes blogs undergo content reorganization: a URL slug is amended or a set of entries moves to a new section. If the links to the blog were posted somewhere on the Internet, it makes sense to ensure the visitors won’t get a 404, unless it’s intended. At the moment, Cloudflare Pages supports the basic set6 of redirection messages with a _redirects file inside the project. It’s a simple way not to lose traffic.

URL rewrites, header modification, even HTTP GET query string manipulation is available at the domain menu section. The only downside is you can have only three Page Rules and two Transform Rules for a free tier.

Scrape Shield

Scrape Shield is an excellent way to put your contacts in the wild. I have a plain text contact email on my About page with Email Address Obfuscation turned on.

~ ❯❯❯ curl https://gdmka.me/about/ | grep "reach me out at" | fold -w 80
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  8514    0  8514    0     0  39971      0 --:--:-- --:--:-- --:--:-- 39971
<p>Currently I&rsquo;m looking for a new challenging job that offers relocation,
 so don&rsquo;t hesitate to reach me out at <a href="/cdn-cgi/l/email-protection
#6700030a0c060627000a060e0b4904080a"><span class="__cf_email__" data-cfemail="da
bdbeb7b1bbbb9abdb7bbb3b6f4b9b5b7">[email&#160;protected]</span></a>. Feel free t
o message me your comments, ideas about the blog as well.</p>

As you can see, Cloudflare does all the heavy lifting: scans HTML for email addresses and serves sanitized pages to what appears to be bots.

The only caveat is that obfuscation didn’t work with the headless browser. Most likely this is due to good score of request IP address.

~ ❯❯❯ ./Chromium --headless https://gdmka.me/about --dump-dom | grep "reach me out at" | fold -w 80

<p>Currently I’m looking for a new challenging job that offers relocation, so do
n’t hesitate to reach me out at <a href="mailto:[email protected]">[email protected]
om</a>. Feel free to message me your comments, ideas about the blog as well.</p>

I don’t have any custom content that requires harvesting protection, but if you do — Server-side Excludes is what you need7.

Built-in Analytics

All Pages projects provide one-click activation to ethical web analytics. While it’s not as sophisticated as Google Analytics, it’s enough to get the basic insights. I don’t know any other JAMStack platform that provides free analytics.

Auto Minify and Brotli

I don’t use any automation to minify or even merge HTML, CSS and JS together simply because I don’t care to. If you are like me, Auto Minify will come in handy to do the job for you.

Combined with Brotli compression8, the final asset size was reduced by almost 89% when transferred over the wire. CF-Polished: origSize=44772 shows the original size of the CSS file in bytes (~ 45KB), CF-BGI: minify response header indicates that Cloudflare served a minified version and Content-Encoding: br that Brotli algorithm was applied. The end result is a compressed 5.43KB style.css with just two mouse clicks!

Other nice out of the box features

As far as I know, none of the competitors to Cloudflare Pages is able to brag HTTP/3 support. While the benefits may not be obvious with a fast speed connection, it shows superior performance on limited connections. The protocol is currently a draft meaning it doesn’t have a wide adoption on the smartphones9 that suffer packet loss the most.

I’ve found Bot Fight Mode exceptionally useful for my side projects. It may become useful again once I add a comment system.

And to conclude, the more feature rich the platform is — the better it scales for your future needs. Therefore Workers and Workers KV are good options to hack where static site generator capabilities will be limited.


  1. https://en.m.wikipedia.org/wiki/Timeline_of_GitHub#Big_picture ↩︎

  2. https://blog.cloudflare.com/cloudflare-pages-ga/ ↩︎

  3. https://www.githubstatus.com/history?page=3 ↩︎

  4. https://www.cloudflarestatus.com/history?page=3 ↩︎

  5. https://developers.cloudflare.com/cache/about/default-cache-behavior#cloudflare-cache-responses ↩︎

  6. https://developers.cloudflare.com/pages/platform/redirects ↩︎

  7. https://support.cloudflare.com/hc/en-us/articles/200170036-What-does-Server-Side-Excludes-SSE-do- ↩︎

  8. https://support.cloudflare.com/hc/en-us/articles/200168396 ↩︎

  9. https://caniuse.com/http3 ↩︎