In this tutorial we will show you how to take advantage of Nginx caching to speed up your WordPress web application.

2020 Update : Easy Nginx FastCGI/Proxy Cache in RunCloud

IMPORTANT! For RunCloud users, we have implemented Nginx Caching in our new feature, RunCache, as part of RunCloud Hub.

You can apply RunCache to your web application from RunCloud dashboard without having to do manual setup from this post.

Using RunCache in RunCloud Hub, you will also get extra features, including cache exclusion and cache preloading.

Latest guide on how to install RunCache and RunCloud Hub →

Latest guide on how to use RunCache Nginx FastCGI/Proxy Cache →

Nginx Caching vs Varnish Caching

Varnish is an HTTP Accelerator software that is often used by DevOps and Sysadmins in optimizations to their web server setups.

What many people don’t know however, is that Nginx comes with its own highly performant default caching mechanism, fastcgi_cache. Whilst the vanilla implementation is considered imperfect, due to some inconsistencies with cache purging, the guys at FRiCKLE Labs have solved this problem with their ngx_cache_purge module.

The result is a caching mechanism every bit as performant as Varnish. But one that requires a less complex web server architecture. This means fewer potential points of failure and a more resilient platform solution.

At RunCloud we have implemented this module inside our Nginx build since day one, and this tutorial will take you through the steps necessary to take advantage of it.

Just so you know, we keep good company in our belief in the Nginx caching solution. For example the CEO at MaxCDN has said that  you don’t need Varnish under Nginx. While the guy behind EasyEngine has spoken at length about this subject, saying that he doesn’t need Varnish since Nginx can do everything.

To be honest, like many other systems, I agree with both of them. RunCloud has chosen to use Nginx Caching over Varnish.

Nginx Helper Plugin

Before setting up our configuration, you need to install the Nginx Helper Plugin from rtCamp. This is the same company that created EasyEngine.

After you have installed the plugin, you need to configure the plugin as follows

FastCGI or Proxy Cache?

Inside RunCloud, we offer two web server stacks for you to choose from. You can choose either Native Nginx or an Nginx + Apache2 Hybrid. If you are using the Native Nginx stack, you need to use FastCGI cache. And if you are using the hybrid setup, you need to use the proxy cache. Got it?

Cache Zone Setup (For both Native Nginx and Nginx + Apache2 Hybrid)

Open /etc/nginx-rc/main-extra.conf with your favorite text editor, and paste the config below.

fastcgi_cache_path /var/run/nginx-fastcgi-cache levels=1:2 keys_zone=FASTCGICACHE:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

proxy_cache_path /var/run/nginx-proxy-cache levels=1:2 keys_zone=PROXYCACHE:100m inactive=60m;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_use_stale error timeout invalid_header http_500;
proxy_ignore_headers Cache-Control Expires Set-Cookie;

You may be asking, “why do I need to add both fastcgi and proxy cache?”

Well, this is to give you the option to deploy web applications with either an Native Nginx or Nginx + Apache2 Hybrid stack, without needing to return to edit the configuration. Why not do them both now, does that make sense?

Implementation for Native NGINX

If you are using Nginx + Apache2 Hybrid, skip ahead to the implementation for Nginx + Apache2 Hybrid.

Now you need to know your web application’s name. Remember Linux is case sensitive, so ensure your web application’s name is correct. In this tutorial I will be using {WEBAPP} as a web application name placeholder, wherever you see  {WEBAPP} in this tutorial, remember to change it to your web application name.

Now create and edit /etc/nginx-rc/extra.d/{WEBAPP}.location.main.cache.conf. E.g: If your web application’s name is app-jebat, then it will be /etc/nginx-rc/extra.d/app-jebat.location.main.cache.conf.

Inside there, add the config below

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;
}

location ~ /purge(/.*) {
    fastcgi_cache_purge FASTCGICACHE "$scheme$request_method$host$1";
}

Now create and edit /etc/nginx-rc/extra.d/{WEBAPP}.location.proxy.cache.conf. Inside there, add the following config.

fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache FASTCGICACHE;
fastcgi_cache_valid 60m;
add_header X-RunCloud-Cache $upstream_cache_status;

Once you have have done that, make sure that your Nginx config files are syntax error free by issuing the following command.

# nginx-rc -t

You should receive a message saying there are no errors. If the terminal tells you the syntax check has failed, then return to the previous config files and recheck everything.

Finally, once you have passed the syntax check, restart your Nginx server using the following command.

# systemctl restart nginx-rc

Implementation for Nginx + Apache2 Hybrid

Now you need to know your web application name. Make sure your web application name is correct because Linux is case sensitive. Please remember, I will be using {WEBAPP} as a web application name placeholder. Wherever you see {WEBAPP} inside this tutorial, remember to change it to your web application name.

Now create and edit /etc/nginx-rc/extra.d/{WEBAPP}.location.main.cache.conf. E.g: If your web application’s name is app-jebat, it will be /etc/nginx-rc/extra.d/app-jebat.location.main.cache.conf.

Inside there, add the config below

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;
}

location ~ /purge(/.*) {
    proxy_cache_purge PROXYCACHE "$scheme$request_method$host$1";
}

After that, create and edit /etc/nginx-rc/extra.d/{WEBAPP}.location.proxy.cache.conf. Inside there, add this config.

proxy_cache_bypass $skip_cache;
proxy_no_cache $skip_cache;
proxy_cache PROXYCACHE;
proxy_cache_valid 60m;
add_header X-RunCloud-Cache $upstream_cache_status;

Once you have have done that, make sure that your Nginx config files are syntax error free by issuing the following command.

# nginx-rc -t

You should receive a message saying there are no errors. If the terminal tells you the syntax check has failed, then return to the previous config files and recheck everything.

Finally, once you have passed the syntax check, restart your Nginx server using the following command.

# systemctl restart nginx-rc

Verifying The Setup

To verify your setup is running, you need to inspect the browser response header. If you are using Mac or Linux, luckily Terminal will do the job.

The command you need to run is:

curl -I https://blog.runcloud.io

Change the URL with your own URL. The response that you receive should be similar to.

From this result you can see, the first request was a MISS and then the second was a HIT. Therefore, this demonstrates that Nginx cache is successfully running.

Now you can enjoy both dramatically increased page load speeds and lower server resource usage, great news!