Page caching with Surge and Cloudflare
In this lesson you will learn about the Surge page caching plugin for WordPress. You will install and configure it, and use the Surge events system to integrate with your Cloudflare zone to serve cached requests directly from the edge. You will also add the cache status to your Nginx logs for cache analysis.
Note this lesson covers the Surge page caching plugin for WordPress. If you're looking for an alternative, check out the Batcache lesson!
Surge
Surge is a very simple and lightweight page caching plugin for WordPress. It stores cached requests as PHP files on disk, leveraging the Linux kernel page cache as well as PHP's Opcache.
Given these storage requirements, Surge can't be decoupled from the server, and thus isn't suitable for multi-server environments or use as a separate cache server. However, for single-server environments, Surge is a great fit.
You can install and activate Surge using WP-CLI:
wp plugin install surge
wp plugin activate surge
The plugin doesn't require any additional configuration, as the defaults work
well for most cases. If you do need to alter the configuration, you can do so
with a custom config file and the WP_CACHE_CONFIG constant.
Surge will start caching pages immediately after activation. You can flush the cache using the plugin's WP-CLI command:
wp surge flush
The plugin will issue an X-Cache header with the status of the cache, so you
can easily verify that it's working using curl:
curl -sI https://uncached.org | grep -i x-cache
# x-cache: hit
Surge maintains a
list of
popular marketing query parameters (such as utm_source) that are excluded when
evaluating the uniqueness of a request. Request cookies starting with an
underscore _ are also excluded. This behavior can be further customized by
using your own Surge config.
The plugin uses flags to control cache invalidation. These are already implemented for core data structures as well as some WooCommerce components. Through a custom configuration, these can also be extended to modify Surge's invalidation behavior.
Cloudflare integration
One of the latest additions to Surge is the events system, which allows you to define custom code that runs on every single request.
By default, Cloudflare will not cache non-static HTTP requests. However, by using a custom event along with some zone cache configuration, we can instruct Cloudflare to cache our requests, effectively implementing edge caching with Surge.
These steps are entirely optional, but as you'll see in the upcoming benchmarks, they make a huge difference, especially if your audience is scattered across different regions.
We'll need three things:
- Ensure a correct
Cache-Controlheader is being sent from Surge. - Make sure Nginx serves the correct
Cache-Controlheader for static assets. - Change our Cloudflare zone settings to respect the
Cache-Controlheaders.
Surge
Let's create a new Surge configuration file. I'll place mine in
/sites/uncached.org/public_html/surge-config.php with the following contents:
<?php
$request_callback = function( $args ) {
$status = $args['status'] ?? null;
if ( ! in_array( $status, [ 'hit', 'miss', 'expired' ] ) ) {
return;
}
header( 'Cache-Control: public, max-age=60, s-maxage=60, stale-while-revalidate=30' );
};
return [
'events' => [
'request' => [ $request_callback ],
],
];
Here we're allowing Cloudflare to cache the request for 60 seconds if the cache
status is hit, miss, or expired. We also allow it to serve stale requests
for up to 30 seconds while revalidating its cache, preventing cache stampedes on
high-traffic sites.
You can opt for a longer TTL, but if you do, you'll need to set up proper
invalidation via the Cloudflare API. This can be done with the expire event in
Surge, though that implementation is beyond the scope of this lesson.
Next, we'll need to enable this Surge config in our wp-config.php file:
define( 'WP_CACHE_CONFIG', __DIR__ . '/surge-config.php' );
This constant instructs Surge to load our configuration file when initializing its own config.
Nginx
The default Nginx configuration doesn't usually send any Cache-Control
headers, but because we are going to set Cloudflare to respect our headers, we
need to make sure these headers are accurate for static assets:
This can be done using the expires directive with a map. Let's update our main
/config/nginx/nginx.conf file and set default expires values for various
content types inside the http context:
http {
# ...
map $sent_http_content_type $expires {
default off;
~text/css max;
~application/javascript max;
~image/ max;
~font/ max;
}
expires $expires;
}
Note that we intentionally left out text/html and application/json content
types, since we'll provide cache headers for those manually through the Surge
plugin events. If Surge is deactivated for any reason, those content types will
remain uncached—which is the desired behavior.
Don't forget to reload your Nginx configuration:
sudo systemctl reload nginx.service
Now that the cache headers are in place, let's update our Cloudflare configuration to respect them.
Cloudflare
By default, Cloudflare caches only static assets, and text/html responses are
always served directly from the origin. We can change this behavior with a new
Cache Rule that respects origin Cache-Control headers instead of relying on
Cloudflare's defaults.
This article is for premium members only. One-time payment of $96 unlocks lifetime access to all existing and future content on wpshell.com, and many other perks.