NGINX Caching Tutorial for WordPress

NGINX Caching Tutorial for WordPress

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

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!

Nginx FastCGI caching is only one of the many technologies the RunCloud platform employs to ensure your web applications are snappy and resilient under load, explore this and all the other benefits by signing up for a free trial today. You won’t regret it.

Ready to get started?

Start your free trial today.

Start My 5-Days Free Trial no credit card required

65 responses to “NGINX Caching Tutorial for WordPress”

  1. No offence, but I think a simple page caching like WP-Rocket will give much more better results.

  2. Chip says:

    How about a PHP site with no purge plugin support?
    Edit “inactive=60m;” ?

  3. Billy says:

    Hi,

    I followed the steps as instructed but the nginx helper plugin isn’t purging the cache. I’m havnig to go in manually and do it. Any idea whats up?

    • Billy says:

      OK I think I might see why… the code for main-extra.config calls for the path to be /var/run/nginx-fastcgi-cache but the cache is actually being stored in /run/nginx-fastcgi-cache (no var). I’m going to try removing the var section and reloading nginx and see what happens

  4. Chip says:

    There is this plugin: https://wordpress.org/plugins/nginx-cache/
    I have added path: var/run/nginx-fastcgi-cache but plugin wont work. Is that the correct path?

  5. Billy says:

    Still have the same problem. Cache won’t clear no matter what plugin I use. I think, and you tell me, the issue may be with the permissions set in the cache folder itself?

    Chip, in the mean time clear it using SSH.

    cd /run/nginx-fastcgi-cache
    rm -rf *

    Cache is cleared and will start to rebuild.

    • admin says:

      we noticed that purging all cache didn’t work. But it works when adding new post or adding new comment. This is due to the caching module itself doesn’t receive purge all cache command. So, the plugin doing rm -rf behind the scene and that won’t work because inside runcloud, nginx user is not web app user.

      • Billy says:

        Hmmm ok interesting — that makes sense. I assume you don’t have a workaround just yet or you would have included it. I’ll see what I can find out over the weekend.

        In the meantime — would it be best to set the site or app name for each site on the /var/run/nginx-fastcgi-cache line?

        Like /var/run/nginx-fastcgi-cache/app-name

        If I’m running multiple sites/apps on the same server/runcloud?

        • Scott says:

          Having the same issue on an Apache/NGINX hybrid of a site I migrated in. Initial loading of site had screwed up pages and the “purge” function in the nginx helper plugin is not purging the entire cache. I had to manually delete all files/folders in /var/run/nginx-proxy-cache to get the site to load.

          Will a workaround even be possible?

          • Billy says:

            Nothing on my end yet but ignore my question about the path to the caching folder. I see now that fastcgi_cache_key handles that

          • Scott says:

            I’ve been banging my head against this “flush entire cache” issue and would really love some insight from RunCloud.

            I came to the same conclusion as https://github.com/FRiCKLE/ngx_cache_purge/issues/10#issuecomment-24024716 did. The unlinkRecursive function is just recursively deleting folders, which won’t since the web app user doesn’t have permissions. I tried to solve by following the next comment there, which suggested I “add PHP process user to nginx users’ group”. I made a new group, assigned the user my web app is running under and chmod /var/run/nginx-proxy-cache to give that group ownership. I also added define(‘RT_WP_NGINX_HELPER_CACHE_PATH’,’/var/run/nginx-proxy-cache/’); to wp-config.php to point to the correct folder and added that path to my web app’s OPEN_BASEDIR paths. Still no luck.

          • Jeff Cleverly says:

            I think there isn’t any workaround yet. The guys behind the plugin haven’t found one. Perhaps the only solution would be to have this caching functionality built into the RunClouad dashboard per webapp with a purge cache button. The RunCloud platform is only a year old, and incredibly powerful and good value compared to it’s direct competitors, so I am not too fussed about this, fingers crossed they work out a solution in future. And remember, the cache clears perfectly well for things like post and page updates, it’s just the purge all that we need to login to the server to do.

            In any case, what I’ve done is updated the code so that my cache is stored in my User login folder at the same level as my webapps, and mounted that folder in memory (tmpfs – got the instructions from the EasyEngine page about using the NGINX helper plugin). I’ve also adjusted it so that each site has its own separate cache.

            It isn’t a complete solution, but it means I can just SSH into my server and my cache folders are all there immediately, which makes deleting them a bit easier/faster than having to change directory to var/run and then delete the entire cache for all the sites.

  6. Adrian says:

    I’m looking forward to have this integrated with only one click and also wp-cli

  7. Faizan says:

    Does runcloud provide all the WooCommerce configurations for NGINX as well with WordPress installation?

  8. DSWONG says:

    Nginx helper doesn’t flush when requested.
    Have to delete cache manually from terminal.
    Run in terminal to remove cache in folder without deleting the folder :
    rm -rf /var/run/nginx-fastcgi-cache/*

  9. Simon says:

    Same problem here, no way to clear the nginx fastcgi cache from WordPress itself, only via ssh.

    This is suboptimal, has anyone found a solution yet?

    Thanks

  10. Nik says:

    Any updates when we can get a nginx cache we can manually flush in WordPress? The article isn’t very useful without any option to flush. It would be great to see the Rocket-Nginx integration as well. Is it on a roadmap or similar?

  11. DSWONG says:

    If you are using WP with woocommerce: you’ll need to add the following to ask fastcgi cache not to cache woocommerce related pages etc to
    /etc/nginx-rc/extra.d/{WEBAPP}.location.main.cache.conf

    by using your favourite editor, mine is NANO.

    ************Start here ***************

    Skip cache on WooCommerce pages

    if ($request_uri ~* “/store.|/cart.|/my-account.|/checkout.|/addons.*”) {
    set $skip_cache 1;
    }

    Skip cache for WooCommerce query string

    if ( $arg_add-to-cart != “” ) {
    set $skip_cache 1;
    }

    #true only when the cookie exists
    if ( $cookie_woocommerce_items_in_cart ) {
    set $skip_cache 1;
    }
    **************End here************

    If you are using W3 total cache, add the following

    ************Start here ***************
    location ~ ^/wp-content/cache/minify/(.+.(css|js))$ {
    try_files $uri /wp-content/plugins/w3-total-cache/pub/minify.php?file=$$
    }
    **************End here************

    Ressource : https://gist.github.com/pelmered/616efcde63c17a4dc3cd

  12. Derrick D Threatt says:

    can you just run a cron job to clear the cache ever 5-10 mins??

  13. Derrick D Threatt says:

    I just followed this tutorial and its clearing my cache when I update a page. I havent tried to add a new post yet.

    • admin says:

      It works if you’re updating a page, create a new post or leave a comment. But it won’t clear cache if you try to purge all cache

      • Simon says:

        Would be stellar to have a solution for purging the cache without having to SSH into the server and issue an rm command.

        Any ideas?

  14. Luke Cavanagh says:

    Server-side caching will always beat a WordPress plugin for caching.

    • Jeff Cleverly says:

      Definitely. I keep having this discussion in the WordPress speed up Facebook group.

      Another great thing about NGINX caching is that it will continue to serve your static cached pages, even if your server PHP has gone down, that’s really cool.

  15. Derrick D Threatt says:

    so now i had to delete a plugin and even if I clear the folder in /run the cache is not cleared. this is insane. any help??

  16. Xelance says:

    For all of you guys who are still having the cache purging issue, you might want to try adding /var/run/nginx-fastcgi-cache to your OPEN_BASEDIR list in your Web Application settings.

    • admin says:

      that isn’t going to help because the created cache file is owned by runcloud-www while the web app owner is “runcloud” or other user

  17. Billy Engler says:

    Are you ever going to fix this? I know someone mentioned server-side clearing is better than a plugin but not for those of us with clients who need to purge cache themselves and without having to post.

    I ended up having to cancel my account with you guys and I HATED doing it but I needed cache purging to work cause of my clients.

    If it ever gets fixed please post an update as I would love to come back!

  18. Scott says:

    Any update on this? I was considering developing something myself for my own clients but decided to check here first and saw this.

  19. Cim says:

    Hi I was just wondering what’s the timeline on RunCloud’s own nginx purge cache plugin release?

  20. Hey guys,

    If you’ve followed this tutorial, just add these lines to your WordPress functions.php:

    function ss88_purge_nginx($post_id)
    {
    wp_remote_get(home_url() . ‘/purge/*’);
    }

    add_action(‘edit_post’, ‘ss88_purge_nginx’);

  21. Alina says:

    Здравствуйте! 123___NGINX caching tutorial for WordPress on the RunCloud Platform___123

  22. If I’m using w3 total as cache plugin, do I need nginx cache plugin?

  23. SH says:

    I’m having a strange problem with this. I have three websites configured the same way. The one without www prefix gives wrong location, / instead of https://domain.tld. This results in Safari trying to open localhost. Chrome can handle this though. Problem is fixed by clearing cache but I’m not sure if it will occur again.

    Connection state changed (MAX_CONCURRENT_STREAMS updated)!
    < HTTP/2 301
    < server: nginx
    < date: Mon, 09 Jul 2018 05:45:25 GMT
    < content-type: text/html; charset=UTF-8
    < content-length: 0
    < location: https:///
    < referrer-policy:
    < x-runcloud-cache: HIT
    <

  24. zatto says:

    Any update on the solution or the plugin for WordPress? Would it be an easier and similar solution to just use varnish? Wp rocket has support for purging Varnish cache and so does w3tc. What about rocket nginx module?

  25. Alex says:

    You guys said you have a solution 5 month ago, is there any progress on it?
    “Admin February 7, 2018 at 8:43 am
    Yeah. We got a solution. However, we need to build our own plugin for the solution to works. Will do a new blog post once we have modified the original plugin”

    • Jeff Cleverly says:

      The technical team identified a solution some months ago, but we have now tested the solution, it works and a beta plugin is in the works. It is coming very soon.

  26. Kiril says:

    Any update on the solution or the plugin for WordPress?

  27. Erik says:

    One option is to add openlitespeed as a webserver option. That way you get varnish cache like system and wordpress plugin which also supports woocommerce out of the box. I think this is the safest way to run woocommerce on a super cache.

  28. Arman says:

    Hi there, happy new customer here.

    Is it possible to have a blog post about Woocommerce configuration for nginx caching with plugins like WP super cache and how to implement Rocket-Nginx for Wp Rocket.

    Or even better, having this auto-setup in Runcloud for each app installation in the wizard, would be awesome.

    I don’t want to overburden you with all these requests.

    But I believe doing so will attract even more noob users like me to adopt your wonderful platform.

    If you need beta tester for your plugin, I’ll be more than happy to test it for you.

  29. Nils says:

    I’d have to echo your your Rocket-Nginx tutorial request. In the first comments on this thread, the team mentioned they’d do a tutorial but I’m yet to see one.

    Also looking forward to the testing the plugin when it comes out.

  30. Tim says:

    Hi Guys!

    Any news about the plugin?

  31. Steve says:

    Hi Guys any news on the plugin ?

  32. Vincent says:

    Hello,
    Any update on the solution or the plugin for WordPress?

  33. nqserv says:

    Hi Jeff,

    Any news or update on this? Thanks

  34. Alex says:

    This is obviously a requested future by your users, why don’t you try to actually provide what is searched for instead of what you think is needed?

  35. Vangelis says:

    Hi,
    after setting the nginx config the first page is uncached for me:
    x-runcloud-cache: MISS
    If i retry with curl -I https://domain.com then i am getting
    x-runcloud-cache: HIT

    It should state a HIT cause there is a lot of traffic on this domain.
    Am i missing something?

    Greets

  36. Chad says:

    Anyone managed to get Rocket-Nginx working? I emailed the team and they seemed very confused, telling me not to install WP-Rocket since it may break my server. I’m using it just fine, but want the NGINX extension.

  37. alex says:

    Seriously, is update ever coming to this request?

Leave a Reply

Your email address will not be published. Required fields are marked *