User Tools

Site Tools


cloudflare_workers

Improving WordPress Speed with Cloudflare Workers

This was originally posted on my blog in December 2018 and has now been pasted here for completeness.

I no longer run this code and I no longer recommend Cloudflare.

Cloudflare Workers allows Javascript code to be run server-side within Cloudflare’s datacenters during the connection between the client and Cloudflare’s regular servers. The code I wrote essentially checks for WordPress cookies and if they’re found then the request is passed through to my origin server as usual, however, if there aren’t any WordPress cookies then Cloudflare’s cache is used. This means that logged out users will get a cached page from their local Cloudflare datacenter and logged in users will be passed straight through to the origin so they get personalised pages.

I used Pingdom Tools to test the speed of the website from Sydney (which is about as far from my origin server as you can be) both with Cloudflare Workers and without. With Workers and caching enabled the page was able to be fetched in 181ms instead of 1305ms for the uncached page; a difference of over one second.

Page timings without Cloudflare Workers

The uncached (no Cloudflare Workers) page speed

Page timings with Cloudflare Workers enabled

The cached page speed using Cloudflare Workers

The x-cache header is added by my origin and the x-cfw-cache is added by my Javascript Worker.

The code I used is as follows:

/*I make no guarantees this code will work reliably. Use at your own risk. Please thoroughly test before deploying.
Enabling this on a Cloudflare Worker for a Wordpress site should cache all HTML pages (if your origin headers allow that) but bypass the cache when a user is logged in.
This is tested and working on a Wordpress 5.0.2 installation and the free Cloudflare tier (but I make no guarentees it will work for anyone else).
Sets the `x-cfw-cache` header to indicate the Worker cache status (either HIT, MISS, NO, or BYPASS): `NO` = server has set cookies (won't cache) and `BYPASS` = client has cookies (bypassing cache).
*/

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event))
})

async function handleRequest(event) {
  let request = event.request;
  let response = null;
  cookies = request.headers.get("Cookie");
  if (cookies && cookies.toLowerCase().includes("wordpress_")){
    console.log("We have cookies. Don't cache.", cookies);
    response = await fetch(request);
    response = new Response(response.body, response);
    response.headers.set("x-cfw-cache", "BYPASS");
    return response;
  }
  let cache = caches.default;
  response = await cache.match(request);
  if (response && response.status !== 200){
    response = null;
  }
  if (!response){
    console.log("No cache. Will fetch.");
    response = await fetch(request);
    response = new Response(response.body, response);
    let responsecookies = response.headers.get("Set-Cookie");
    if (responsecookies && responsecookies.toLowerCase().includes("wordpress_")){
      //Wordpress auth/test cookies are being set here. We don't want to cache.
      response.headers.set("x-cfw-cache", "NO");
    } else {
      
      response.headers.delete("Set-Cookie"); //Cloudflare won't cache responses containing Set-Cookie.
      response.headers.set("x-cfw-cache", "MISS");
      if (response.status == 200){
        event.waitUntil(cache.put(request, response.clone()));
      }
    }
  } else {
    response = new Response(response.body, response);
    response.headers.set("x-cfw-cache", "HIT");
  }
  
  return response
}

This code is also available as a GitHub Gist

Most of my debugging code is still present to make it easier to understand. By enabling Workers on Cloudflare and using the above code, you should get Cloudflare to safely cache your WordPress HTML assuming your origin sends valid public cache headers for HTML pages. Workers is priced based on the amount of requests that pass through them so it’s best to disable them when unneeded; in my configuration I have Cache Everything enabled and Workers disabled for /wp-includes/* and /wp-content/* as those directories only contain static content and can be cached the same for everyone without using Workers – This saves a large amount of requests hitting Workers unnecessarily and will save money for popular sites.

Pingdom has reported my hourly average homepage load time worldwide as 242ms and 252ms for the last 2 hours whereas it was around 510ms to 530ms prior to enabling Workers with caching.

cloudflare_workers.txt · Last modified: 2023/02/18 15:34 by 127.0.0.1