Object Cache

An object cache stores potentially computationally expensive data such as database query results and serves them from memory. This greatly improves the performance of WordPress as there is no longer a need to query the database on every page load for information already stored within the object cache.

Redis is the latest and greatest when it comes to object caching. However, popular alternatives include Memcache and Memcached.

To install Redis, issue the following commands.

sudo apt install redis-server
sudo apt install php7.0-redis

It’s also a good idea to set a maximum memory usage. As I’m only using a 512Mb server, I set mine to 64mb.

sudo vi /etc/redis/redis.conf

Uncomment the line # maxmemory and set the desired value.

maxmemory 64mb

Save the configuration and restart both Redis and PHP-FPM.

sudo service redis-server restart
sudo service php7.0-fpm restart

In order for WordPress to make use of Redis as an object cache you need to install the Redis Object Cache plugin by Till Krüss.

Object Cache - Plugins Screen

Once installed and activated, go to Tools > Redis to enable the object cache. Once the Object Casche is enabled you now can Flush the cache if required or diable it again:

Object Cache - Flush

Object caching reduces the average amount of database queries on the front page from 22 to 2, the database server is still being hit. Establishing a database connection on every page request is one of the biggest bottlenecks within WordPress.

The benefit of object caching can be seen when you look at the average database query time, which has decreased from 2.1ms to 0.3ms. The average query times were measured using Query Monitor.

In order to further improve performance and decrease server resource usage you need to bypass PHP altogether. Enter page caching…

Page Cache

Although an object cache can go a long way to improving your WordPress site’s performance, there is still a lot of unnecessary overhead in serving a page request. For many sites, content is rarely updated. It’s therefore inefficient to load WordPress, query the database and build the desired page on every single request. Instead, you should serve a static HTML version of the requested page.

Nginx allows you to automatically cache a static HTML version of a page using the FastCGI module. Any subsequent calls to the requested page will receive the cached HTML version without ever hitting PHP.

Setup requires a few changes to your Nginx server block, so open your virtual host file.

sudo vi /etc/nginx/sites-available/www.machinimatrix.org

Add the following line before the server block, ensuring that you change the fastcgi_cache_path directive and keys_zone. You’ll notice that I store my cache within the site’s directory, on the same level as the logs and public directories.

fastcgi_cache_path /home/ashley/ashleyrich.com/cache levels=1:2 keys_zone=ashleyrich.com:100m inactive=60m;

You need to instruct Nginx not to cache certain pages. The following will ensure admin screens and pages for logged in users are not cached, plus a few others. This should go above the first location block.

set $skip_cache 0;

# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
    set $skip_cache 1;
}   
if ($query_string != "") {
    set $skip_cache 1;
}   

# Don’t cache uris containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
    set $skip_cache 1;
}   

# Don’t use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
    set $skip_cache 1;
}

Next, within the PHP location block add the following directives.

fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache ashleyrich.com;
fastcgi_cache_valid 60m;

Notice how the fastcgi_cache directive matches the keys_zone set before the server block. In addition to changing the cache location, you can also specify the cache duration by replacing 60m with the desired duration in minutes. The default of 60 minutes is a good starting point for most people. Once happy, save the configuration.

Next you need to add the following directives to your nginx.conf file. The first instructs the FastCGI module on how to generate key names and the second adds an extra header to server responses so that you can easily determine whether a request is being served from the cache.

sudo vi /etc/nginx/nginx.conf

Add the following below the Gzip settings.

##
# Cache Settings
##

fastcgi_cache_key "$scheme$request_method$host$request_uri";
add_header Fastcgi-Cache $upstream_cache_status;

Save the configuration and restart Nginx.

sudo service nginx restart

Now when you visit the site and view the headers, you should see an extra parameter.

Nginx - Response Headers

The possible return values are:

  • HIT – Page cached
  • MISS – Page not cached (refreshing should cause a HIT or BYPASS)
  • BYPASS – Page cached but not served (admin screens or when logged in)

The final step is to install the Nginx Cache plugin, again by Till Krüss. This will automatically purge the FastCGI cache whenever your WordPress content changes. You can also manually purge the cache from the WordPress dashboard.

Once installed, navigate to Tools > Nginx and define your cache zone path. This should match the value you specified in your Nginx hosts file.