Nginx, WordPress Network, and Fastcgi Cache: The Ultimate Guide.

Update: new sections in the nginx config for handling the wordpress admin section!

Update: new upstart script.
Update Feb 9, 2016 No longer need ngx_cache_purge compiled in, Ubuntu 14.04+ specific.

In honor of Antirez’ fantastic post here: On the web server scalability and speed are almost the same thing, I’m sharing my Nginx configuration for WordPress Network (previously WordPress-Mu).

I’m assuming you are running ubuntu and you know the basics of system administration. I’m also assuming you’re using some sort of fastcgi backend. I suggest this excellent howto from interfacelab as an excellent starting point.

First, go get the nginx mainline PPA. Might need to install common-software-properties first.

Next,in your nginx.conf, add this line in the http section:

This creates a cache of 64MB. It’s stored in memory, so be sure you’ve got overhead. If you’re running a blog, unless you’ve got HUGE files, it’s unlikely you’ll need this much cache, and you can probably safely pare this down further to save memory.

And the final piece, the server configuration for nginx. Note the usage of the variable $nocache, and also the purge location.

Be sure to install the nginx_proxy_cache_purge plugin, and activate it network wide. And that’s it!

Just for kicks, try:

Post your results in the comments!

If you happen to be using a recent ubuntu, try this out for your upstart script


  • April 9, 2011 - 1:59 am | Permalink

    Great article.

    Have you considered:
    1. Adding $request_method to fastcgi_cache_key so that (for example) HEAD requests wont create empty cache results
    2. Adding restrictions (IP) to /purge for security reasons (localhost/public IP for purge plugin).
    3. Using an alternative to the expensive ms-files rewrite (see WP codex for an example)

    Where are your AB results? :)

    Have you tried services like for third party performance testing of your config?

    • admin
      April 11, 2011 - 11:53 am | Permalink

      I haven’t tried (hadn’t heard of them before), but I will look into it.

      I’ll update the ms-files rewrite and the $request_method: both are good points.

      as for performance, I’m now getting over 5k requests per second when I run apache bench from localhost, versus around 100 requests per second prior to the change. That’s a 50x performance boost!

  • Alex
    April 27, 2011 - 7:03 am | Permalink

    OK, I’ve been messing around with a similar config but for Multisite blog. I have one problem with fastcgi caching and so far unable to figure it out:

    Plugins using CAPTCHA – don’t work properly because pages are served from cache. Specifically these 2 plugins I use:

    Peter’s Custom Anti-Spam
    DD FormMailer

    I know there has to be a way to exclude those from being cached but am still in process of figuring all things out – any chance you know a solution for this?

    • admin
      April 27, 2011 - 7:45 am | Permalink

      Hey Alex, that’s an interesting problem. My guess is that the solution has to do with either a specific non-caching location directive for the captcha form or modify the captcha plugin to append a timestamp to the image request to break the cache.

      This blog doesn’t have a spam problem, but I have used akismet and wp-hashcash to great effect with this configuration.

  • Alex
    April 27, 2011 - 7:55 am | Permalink

    Yep, I understand – my problem is – it is a multisite blog, serving my customers – i Have to find a solution to exclude caching of captcha functions from fastcgi.

    Knowing how to get it done will also help with any future issues, I suspect timthumb.php used by many of the Premium Themes will be next issue :D

    • admin
      April 27, 2011 - 8:04 am | Permalink

      I’m travelling at the moment, so it might take me a while to get back to you, but send me a link to the plugin you are using and I will see if there is an easy solution.

  • Alex
    April 27, 2011 - 8:15 am | Permalink


    here are links:

    1st activate through mu-plugins, and second per individual blog, as needed or requested by customer. While I don’t think it will make much difference.

    Thanks again!
    Am still trying to work out all the fastcgi details, obviously not much experienced with it :-)

    • admin
      April 27, 2011 - 8:17 am | Permalink

      I will take a look and let you know if I find a solution

    • admin
      April 29, 2011 - 4:34 pm | Permalink

      I would check for the url for the specific url for each plugin, like

      if you use a regex to look for that url, you could set $no_cache=”Y”


  • Alex
    April 27, 2011 - 10:36 am | Permalink

    Thanks, appreciate you taking the time

    • admin
      April 29, 2011 - 5:21 pm | Permalink

      Also, it can be handy to add a header with the value of $no_cache in the process of debugging these things

  • Eleshar
    September 8, 2011 - 11:54 am | Permalink

    Thanks for the great post.

    I’m having some difficulties getting my setup to work.

    Are you aware of any issues with the last stable nginx build version 1.0.6? My fastcgi_cache_path directory is being created, but it remains empty, so no files is being cached :(

    • admin
      September 9, 2011 - 10:16 am | Permalink

      Hmmm. I am running 1.0.6 now. Post your configuration and I will take a look.

      • Eleshar
        September 9, 2011 - 1:49 pm | Permalink

        Thank you for the reply, I really can’ t figure out why it’s not working and I so desperately want to get it working, this is my config for a normal WP site.

        • admin
          September 9, 2011 - 2:39 pm | Permalink

          So, first and foremost, I would suggest double checking to make sure the user fmmsync and the group www-data can write to /var/cache/nginx
          Secondly, It looks like you are passing the connection off to php before you are executing the cache. You want to include the fastcgi params first, then execute the cache, then move on the the fastcgi param configuration, and then finally send the connection back to php. Change the order of your configuration directives to something more like this:

          Third, it looks like your cache purge key and cache key are different:

          additionally, make sure you are testing with a browser that isn’t logged into your wordpress instance. I like to add a header to the response to check wether or the the request would have been cached, or called from the cache:

          This will return empty if the cache ought to have been used, and with “y” if the cache is bypassed.

          Aside from that, I would simplify your fastcgi_cache_path directive. Once you’ve got it caching something, try adding directives to optimize.

          For even more speed, try putting the cache on a tmpfs!

          Hope this helps!

          • Eleshar
            September 10, 2011 - 2:32 am | Permalink

            Unfortunately that didn’t make a difference, but I finally figured out why it wasn’t working.

            I had zlib.output_compression active in php.ini, once I deactivated that it started working.

          • admin
            September 10, 2011 - 12:55 pm | Permalink

            Yeah, I would let nginx do the compression, instead of php. Glad you got it fixed!

  • December 3, 2011 - 6:54 pm | Permalink

    after reading your post I set out to try to upgrade and configure my nginx installation to meet the specs. after make install, what are the other commands to get it to startup? the older installation had a /etc/init.d start process

  • December 4, 2011 - 7:35 pm | Permalink

    disregard my last post, I was able to get it installed correctly.

  • admin
    May 27, 2012 - 1:10 pm | Permalink

    Minor additions to deal with w3-totalcache minifying javascript and using a cdn.

  • June 2, 2012 - 8:31 am | Permalink

    It’s a good post.

    • admin
      June 25, 2012 - 4:58 pm | Permalink

      Thanks! I try to keep it up to date as I update my config.

  • WP
    June 24, 2012 - 3:49 am | Permalink

    Thanks for the useful post! I intend to implement fastcgi caching that you’ve outlined, but as I’ll be running on the smallest Linode (512RAM, 20GB HDD), I’m wondering whether the settings under the http block will be excessive for a small VPS. I’d really like to hear your advice. Thanks for your time!

    • admin
      June 25, 2012 - 2:44 pm | Permalink

      Hey! So, I run this blog on a $20 linode vps. The fastcgi caching is all disk based, the way it is setup here, so it shouldn’t impact your memory footprint. Additionally, if you are caching correctly, you should be able to get away with a relatively small number of php-fpm processes. I have three nginx workers and two php-fpm processes. I run a few other blogs on this same host, some of whom have been boingboing’ed without breaking a sweat. Additionally, you can really crank down the memory usage for mysql as well from the standard config, if you are so inclined. If you are interested, I’ll write up a blog about how I’ve setup my linode as well.

      • WP
        July 5, 2012 - 11:32 pm | Permalink

        Thanks for your reply! I’d love to hear how you crank down your memory usage for MySQL, and yes, it’d be great if you can share your Linode set up too. Thanks!

        • admin
          July 6, 2012 - 5:22 pm | Permalink

          okeydoke. I’ll put together another post and let you know. I think one for the linode and another for mysql probably makes sense….

  • August 9, 2012 - 3:36 am | Permalink


    I checked your site with curl, and there is “Last-Modified” tag in it:

    How did you do that? Did you host your own site on VPS? Mind to share the nginx conf?


    • admin
      August 9, 2012 - 10:48 pm | Permalink

      hey! so, this is the config that I use for nginx on my linode. I also use w3-total-cache, which I believe adds those headers.

  • Pingback: Webserver Extrem-Tuning (für z.B. Wordpress). Teil 1: nginx, php-fpm & php-apc installieren | Kristian Söhl

  • Pingback: WordPress deployment: super simple and super fast with nginx caching »

  • Pingback: Nginx + fastcgi_cache 加速 | WP奇才

  • Leave a Reply

    This site uses Akismet to reduce spam. Learn how your comment data is processed.