Cache AJAX GET Requests with Cloudflare and Varnish

AJAX requests are typically used to provide dynamic content on WordPress sites and bypass cache. I have already shown how to Cache AJAX requests with Varnish to bypass PHP and MySQL for AJAX processing by storing the cache in Varnish. In my quest for maximum performance I also experimented with Cloudflare page caching for WordPress. This guide combines the power of these two guides, we are going to cache AJAX GET requests from WordPress on Cloudflare for the fastest load times.

This guide assumes you are using Varnish 4 and have a free Cloudflare account.

Before and After Benchmarks

The before result shows a 307 ms load time to California from the Netherlands (proof).

The after result shows a 3 ms load time to California from the Netherlands after using Cloudflare page caching (proof).

This is a huge improvement of 3 ms down from 307 ms. That is roughly 1% of the original load time for the WordPress popular posts widget.

Cache AJAX GET Requests with Cloudflare and Varnish

Let’s look at the headers of the AJAX request to see why Cloudflare isn’t caching them using cURL.

curl -I "https://guides.wp-bullet.com/wp-admin/admin-ajax.php?action=wpp_get_popular&id=3"

The Expires and Cache-Control headers tell Cloudflare to not cache this URL. You can see this in the CF-Cache-Status: MISS header.

[email protected]:~# HTTP/1.1 200 OK
Date: Fri, 13 Jan 2017 18:59:53 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Set-Cookie: __cfduid=d6303005caebe1f2b9037a66ba01d211b1484333992; expires=Sat, 13-Jan-18 18:59:52 GMT; path=/; domain=.htpcguides.com; HttpOnly
Pragma: no-cache
X-Robots-Tag: noindex
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Vary: Accept-Encoding
X-Varnish: 1087020866
Via: 1.1 varnish-v4
Access-Control-Allow-Origin: https://guides.wp-bullet.com
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Cache: HIT
CF-Cache-Status: MISS
Server: cloudflare-nginx
CF-RAY: 320b167eaaee0c5f-AMS

We can manipulate these headers with Varnish 4 by modifying the vcl file.

sudo nano /etc/varnish/default.vcl

Add this snippet in vcl_deliver to remove the offending headers and add the right Cache-Control header so Cloudflare will cache this request.

sub vcl_deliver {
    if ( req.url ~ "\?action=wpp_get_popular" && !req.http.cookie ~ "wordpress_logged_in" ) {
        # Remove headers preventing Cloudflare cache
        unset resp.http.Cache-Control;
        unset resp.http.Expires;
        unset resp.http.Pragma;
        unset resp.http.ETag;
        # Cache request in browser for 1 day (in seconds)
        set resp.http.Cache-Control = "max-age=259200";
    }
}

Check your Varnish vcl syntax is OK

varnishd -C -f /etc/varnish/default.vcl

If there were no errors you can reload Varnish

sudo service varnish reload

Time to verify the header manipulation is working.

Test AJAX Request is Cached

Using the same cURL command we can query the same AJAX GET request

curl -I "https://guides.wp-bullet.com/wp-admin/admin-ajax.php?action=wpp_get_popular&id=3"

You can see the headers are gone and have been replaced with the correct Cache-Control header.

Notice there is now a CF-Cache-Status: HIT.

HTTP/1.1 200 OK
Date: Sat, 14 Jan 2017 10:34:52 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Set-Cookie: __cfduid=d315ec598c4f6ca083628abcc3bef0cdf1484390092; expires=Sun, 14-Jan-18 10:34:52 GMT; path=/; domain=.wp-bullet.com; HttpOnly
X-Robots-Tag: noindex
Vary: Accept-Encoding
X-Varnish: 135206
Via: 1.1 varnish-v4
Cache-Control: public, max-age=2678400
Access-Control-Allow-Origin: http://guides.wp-bullet.com
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Cache: MISS
CF-Cache-Status: HIT
Expires: Tue, 14 Feb 2017 10:34:52 GMT
Server: cloudflare-nginx
CF-RAY: 3210701dead83ce9-CPH

It will not get much faster than caching your dynamic requests on a CDN like Cloudflare :).