This tutorial will show you how to setup caching with Nginx and WordPress. You can combine your Nginx reverse proxy with an open-source WordPress plugin that caches dynamic content. This means you can serve the cached, static HTML files directly with Nginx. This approach takes the best of both worlds: you make use of the speed and low resource needs of Nginx to do most of the work, but you can still use Apache-PHP to handle dynamic queries when the content does not exist in the cache. As I said in a previous post, if you’re using Nginx to serve content directly, you should be aware that it ignores .htaccess files and you need to implement a security policy in addition to what you use for Apache.

I normally advocate using the least number of plugins in a WordPress site, since every plugin adds to the loading time of a page. However, you’ll be using Nginx to directly serve pages once they’ve been created. This makes the small overhead of a cache plugin well worth it. I like WP Super Cache, and I’ll use this in my example.

If you’ve been following my other tutorials, you’ll have an Nginx proxy server that directly serves static content. You need to do a few things:

  1. Install WP Super Cache plugin in your WordPress installation;
  2. Tell Nginx where to find the static files that WP Super Cache will produce;
  3. Give Nginx instructions on what it needs to needs to serve directly and what it needs to proxy on to Apache (we can do 2 & 3 together).

Install WP Super Cache

Installing this plugin is easy: head over to your plugins page, click ‘Add New’, and type “WP Super Cache” in the search box. It should turn up among the top hits.

Click ‘Install Now’, wait a bit, and the click ‘Activate’. WP Super Cache is relatively easy to use and has a less bewildering array of choices than competing plugins such as W3 Total Cache. Once you’ve installed WP Super Cache, we need to go over a few settings.

Head on over to the the ‘Easy’ tab and turn caching on, then save this setting:

Panel to turn caching on or off on WP Super Cache

Turn caching on and save.

Other than taking note of the cache location, which I will go over a little further down, this is really the only essential bit. However there are a few settings worth tinkering with. Firstly head over to the ‘Advanced’ tab, and choose ‘Expert’ mode:

Panel to toggle expert caching on or off

Turn on expert mode

Just below this, lets change a few options. I like to leave caching off for known users, since they tend to visit more often looking for changed content, and to make use of 304 (Not Modified) headers, which significantly speed things up for users:

Miscellaneous options panel on WP super Cache

Toggle on caching for known users and 304 Not Modified headers.

Save your new changes and continue on down the page. Make note of the cache location:

Panel to change the cache location in WP Super Cache

Make note of the cache location.

There are a few other settings in the plugin that you can play with. I like to use preloading, for example. However, nothing else is essential for Nginx to now serve directly from the cache.

Configure Nginx to serve from the cache

The easiest way to accomplish this is to write the cache settings as a snippet, and call it from within your Nginx server block.

Create a file supercache.conf in /etc/nginx/snippets/

root@system:~# nano /etc/nginx/snippets/supercache.conf

And add the content you need for Nginx to find the cache:

set $cache_uri $request_uri;

# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
	set $cache_uri 'null cache';
	}

if ($query_string != "") {
	set $cache_uri 'null cache';
	}

# Don't cache uris containing the following segments
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php
	|wp-.*.php|/feed/|index.php|wp-comments-popup.php
	|wp-links-opml.php|wp-locations.php |sitemap(_index)?.xml
	|[a-z0-9_-\]+-sitemap([0-9]+)?.xml)") {
		set $cache_uri 'null cache';
	}

# Don't use the cache for logged-in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+
	|wp-postpass|wordpress_logged\_in") {
		set $cache_uri 'null cache';
	}

# Set the cache file
# Use index-http.html for plain http delivery, and index-http.html for delivery of ssl content.
set $cachefile "/wp-content/cache/supercache/$http_host/$cache_uri/index-http.html";
#set $cachefile "/wp-content/cache/supercache/$http_host/$cache_uri/index-https.html";

We are using the one file to tell Nginx to exclude some content from the cache, and also where to find it. Update the cache location at the bottom of the file (highlighted red) with the cache location of your installation. The one in this example is the default location.

Now we need to modify the Nginx server file to include the cache settings:

server {
	listen 80;
	server_name example.com www.example.com;
	root /var/www/example.com/html;
	index index.php;

	include snippets/supercache.conf

	location / {
		try_files $cachefile $uri $uri/ /index.php;
	}

	location ~ \\.php$ {
        proxy\_pass http://localhost:8080$request\_uri;
        proxy\_set\_header Host $host;
        proxy\_set\_header X-Real-IP $remote_addr;
        proxy\_set\_header X-Forwarded-For $remote_addr;
        proxy\_set\_header X-Forwarded-Proto $scheme;
    }

	location ~ /\\. {
		deny all;
	}
}

Check that your configuration is correct. If it is you should get a message saying so:

root@system:~# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If all went well, reload the Nginx configurations:

root@system:~# systemctl reload nginx

Congratulations! You’re serving static content and cached pages directly with Nginx, and passing on anything that Nginx doesn’t know how to handle back to Apache. Your server should be able to handle load spikes relatively well.