fastcgi_cache with conditional purging

easyengine (ee) note: If you are using easyengine, you can accomplish everything in this article using command:

ee site create example.com --wpfc

In first part of this series, we have seen many combinations of different WordPress setup with different caching plugins. Today, we will use an altogether different way of caching!

Rather than asking a complex PHP-MySQL application like WordPress to do some extra work for caching, we will ask light-weight Nginx to cache WordPress content on its end.

Nginx has built-in support for fastcgi_cache but it doesn’t have mechanism to purge cached content built-in. So we need to rely on third-party nginx module.  Without this 3rd party module, cache won’t be updated if you create/edit any post/page in WordPress.

Prerequisites

Check if your nginx has fastcgi_cache_purge module

If you have installed Nginx by following our guide, then support for fastcgi_cache_purge should be already there. You can test it by running following command:

nginx -V 2>&1 | grep nginx-cache-purge -o

If you see nginx-cache-purge in output then you already have it.

Otherwise, if you are on Ubuntu with default Nginx installation, you can run following commands to install nginx with fastcgi_cache_purge module.

Reinstall nginx with fastcgi_cache purge module support

sudo add-apt-repository ppa:rtcamp/nginx
sudo apt-get update
sudo apt-get remove nginx*
sudo apt-get install nginx-custom

Install Nginx Helper Plugin

Above step ensures that Nginx can purge a page from its fastcgi_cache selectively. But Nginx cannot automatically find out which page to purge and when to purge?

So install Nginx helper plugin from WordPress plugin repository and activate it. Apart from other features, it provides cache purging options. Just activate it, go to its settings and turn on “Enable Cache Purge” option.

If you want more control over your cache purging rules, you can play with different purging options it provides.

Using ramdisk (tmpfs) for cached content

This step is optional. You need give Nginx a folder store fastcgi_cache content. I will recommend using /var/run on Ubuntu as its mounted as tmpfs (in RAM). If you do not have ample RAM you can pick any other location.

If you are going with RAM, make sure you check size of /var/run folder. Its generally 20% of your total RAM size.

To verify it, run command df -h /var/run. You will see output like below:

Filesystem      Size  Used Avail Use% Mounted on
tmpfs           6.3G  364K  6.3G   1% /run

It looks like we have more than 6GB at our disposal! Our server has 32GB RAM by the way, so 6.3GB is close to 20%

Nginx Config

No matter how you are using WordPress, i.e. single or Multisite (with subdirectory/subdomain/domain-mapping) fastcgi_cache related configuration will remain similar.

Now make changes to /etc/nginx/sites-available/example.comfile so it looks like one below:

#move next 4 lines to /etc/nginx/nginx.conf if you want to use fastcgi_cache across many sites 
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS: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;
server {
	server_name example.com www.example.com;

	access_log   /var/log/nginx/example.com.access.log;
	error_log    /var/log/nginx/example.com.error.log;

	root /var/www/example.com/htdocs;
	index index.php;

	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 / {
		try_files $uri $uri/ /index.php?$args;
	}    

	location ~ \.php$ {
		try_files $uri =404; 
		include fastcgi_params;
		fastcgi_pass 127.0.0.1:9000;

		fastcgi_cache_bypass $skip_cache;
	        fastcgi_no_cache $skip_cache;

		fastcgi_cache WORDPRESS;
		fastcgi_cache_valid  60m;
	}

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

	location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
		access_log off;	log_not_found off; expires max;
	}

	location = /robots.txt { access_log off; log_not_found off; }
	location ~ /\. { deny  all; access_log off; log_not_found off; }
}

The line fastcgi_cache_use_stale is what makes caching on Nginx-side unique. This line tells Nginx to use old (stale) cached version of page if PHP crashes. This is something not possible with WordPress caching plugins.

Don’t Forget

Always test your Nginx configuration and then reload it. All changes to Nginx config must be followed with these commands:

nginx -t && service nginx reload

Must Read

272 Responses to “fastcgi_cache with conditional purging”

  1. Greg Tee

    Wow! Nice work! This is the first complete how-to and configuration that really works well :-)

    I do have 1 request. If I’m not mistaken, the cache of a post does not get purged when you edit a post. I think this rather essential (the homepage does get purged).

  2. Rahul Bansal

    @Greg

    Please use support forum instead. Solution to your issue may help others as well.

    Don’t worry. Nginx-Helper doesn’t log any sensitive information.

  3. Richard

    Thank you for this article. However when I try to install nginx-custom, I receive the following error:

    The following packages have unmet dependencies:
    nginx-custom : Depends: nginx-common (= 1.2.4-1ppa4~precise) but 1.2.4-2ubuntu0ppa1~precise is to be installed
    E: Unable to correct problems, you have held broken packages.

    Does this mean the repo is not updated for my version of nginx?

    • Rahul Bansal

      @Richard

      I have tested everything on Ubuntu 12.04 (precise) which is same as yours.

      Try running following commands:

      nginx_installed=`dpkg -l | grep nginx | awk '{print $2}' | tr "\n" " "`
      sudo apt-get purge $php_installed
      sudo add-apt-repository ppa:brianmercer/nginx
      sudo apt-get update
      sudo apt-get install nginx-custom
      

      Let me know if above works for you.

      • Richard

        Unfortunaltely I receive the same error message as before. I followed the http://rtcamp.com/tutorials/installing-phpapc-mysql-postfix-nginx-and-wordpress-on-ubuntu/ tutorial before this one. Could it be that the nginx-stable repository from that tutorial is conflicting with the brianmercer from this one?

        • Rahul Bansal

          Could it be that the nginx-stable repository from that tutorial is conflicting with the brianmercer from this one?

          Most likely yes! Please remove ppa:nginx/stable from /etc/apt/sources.list.d and try again. Don’t forget to run sudo apt-get update in between.

          Just for info, on our server, I have ppa:nginx/stable and ppa:brianmercer/nginx both coexisting together.

          Alternatively, packages from here http://www.dotdeb.org/instructions/ will also work (most likely)

          • Richard

            I’ve removed the stable from sources, ran the apt-get update and tried installing nginx-custom, but still no luck. Think I will just start from scratch with a fresh install of my server. I was wondering, would you recommend using fast-cgi caching over W3TC, performance wise?

            Also, if I may suggest a future tutorial, it would be about configuring linux for sftp or scp use. Specifically on setting the correct group/user permissions for a root user to add/modify files and folders using filezilla or winscp, while still maintaining ownership to www-data. I’ve tried multiple tutorials found online, but none of them seem to work for me. Anyway, thanks for your help and providing these ningx tutorials to the community. Much appreciated!

          • Rahul Bansal

            @Richard

            I have done some benchmarks but its hard to conclude either way.

            Once a page gets cached, nginx does all the work. So there is not much performance difference for “reading/serving” a cached page.

            In theory, W3TC cached pages will be served faster when small number of pages are cached. For large sites, where 10000’s of pages are cached, fastcgi might be faster.

            In terms of “creating/generating” a cached page, I feel nginx-fastcgi will take less resources.

            Personally, I am using nginx-fastcgi for page-cache everywhere. I also use W3TC for Object-Cache, Database-Cache & CDN.

            ==

            Regarding SFTP, we login with www-data user to edit files. So we never faced any permission issue.

  4. Glenn

    Excellent article, thank you.

    Do you know if it is possible to use a free control panel with the above configuration?

    Thank you.

    • Rahul Bansal

      You can try ISPConfig. I will be posting about in few days. :-)

      • Glenn

        Looking forward to this :)

        It’s the only thing stopping me going ahead and trying this tbh, and I’m looking forward to experimenting with the added speed this would give WordPress, but retaining the ease of having a control panel for day to day task…

        Thanks in advance.

  5. Nick Nasty

    Hi, In order for this line to work

    sudo add-apt-repository ppa:brianmercer/nginx
    

    A Python module had to be installed first on Ubuntu like this:

    sudo apt-get install python-software-properties -y
    

    Without installing that, the command `add-apt-repository1 came back as not being recognized Do you have a repository to use for Ubuntu 10.10? since the one you recommend is for 12.04 which my host (Rackspace) has some problem with.

    Thanks, Nick

  6. Nick Nasty

    Hi, I did. Created a new virtual server with 12.04 followed your instructions from step 1. Now I am on this step and the following line:

    sudo apt-get install nginx-custom
    

    returns back the following:

    Reading package lists... Done
    Building dependency tree
    Reading state information... Done
    Some packages could not be installed. This may mean that you have
    requested an impossible situation or if you are using the unstable
    distribution that some required packages have not yet been created
    or been moved out of Incoming.
    The following information may help to resolve the situation:
    
    The following packages have unmet dependencies:
     nginx-custom : Depends: nginx-common (= 1.2.4-1ppa4~precise) but 1.2.5-1~dotdeb.0 is to be installed
    E: Unable to correct problems, you have held broken packages.
    

    Any ideas what to do? I tried every other suggestion written above on this page? Thanks, NIck

    • Nick Nasty

      Actually I figured it out, had some depository in there that installed nginx that is newer than what the brianmercer/nginx could use.

  7. Abhishek

    Hi ,
    I implemented it the way as described in tutorial but faced serious performance issue , I can see in configuration index.php is not getting cached ? is it so ? Can we enable caching for index.php ? Will the nginx helper plugin will work with it then.

  8. Joe Bunting

    Hi,

    When I try to install, I get the following error:

    E: Unable to locate package nginx-custom

    Any ideas?

    • Rahul Bansal

      @Joe

      Sorry for delayed reply. I am traveling from last 2-3 days.

      Did u forget to run apt-get update after adding sudo add-apt-repository ppa:brianmercer/nginx?

      Please paste here output of command: apt-cache showpkg nginx. It might help me debugging your issue.

  9. Abhishek

    Actualli I did the installation in centos , I recompiled the module with nginx it is the latest stable version so i dont think their is no problem with the package but it may be with the configuration please find below config –

    
    fastcgi_cache_path /data1/nginx-cache1 levels=1:2 keys_zone=WORDPRESS:500m inactive=420m ;
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
    fastcgi_cache_use_stale error timeout invalid_header http_500;
    
    server {
        listen     0.0.0.0:80;                # your server's public IP address
        server_name  www.cannotdisclose.com ;                   # your domain name
        index index.php index.html ;
        root         /data1/www/localhost.com/public_html/;  # absolute path to your WordPress installation
        set $no_cache 0;
        try_files $uri $uri/ /index.php;
    
    location ~ .php$ {
    
    #       include        fastcgi_params;
      #      fastcgi_pass   unix:/var/run/php-fcgi.sock;
       #     fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    
    }
    
    set $no_cache 0;
    add_header    Cache-Control  public;
    expires       modified +10m;
    
    # POST requests and urls with a query string should always go to PHP
        if ($request_method = POST) {
                set $no_cache 1;
        }
        if ($query_string != "") {
                set $no_cache 1;
        }
    
        # Don't cache uris containing the following segments
        if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|registe                                      r|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 $no_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 $no_cache 1;
        }
    
        location / {
                try_files $uri $uri/ /index.php?$args;
        }
    
    location ~ .php$ {
                    try_files $uri /index.php;
                    include fastcgi_params;
    
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    
    fastcgi_pass   unix:/var/run/php-fcgi.sock;
    
    fastcgi_pass   127.0.0.1:9000;
            #fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
       fastcgi_param SCRIPT_FILENAME $request_filename;
    
                fastcgi_cache_bypass $no_cache;
                fastcgi_no_cache $no_cache;
    
                fastcgi_cache WORDPRESS;
                fastcgi_cache_valid  420m;
        }
    
        location ~ /purge(/.*) {
            fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
        }
    
        location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpe                                      g|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
                access_log off; log_not_found off; expires max;
        }
    
        location = /favicon.php { access_log off; log_not_found off; }
        location = /robots.txt { access_log off; log_not_found off; }
        location ~ /\. { deny  all; access_log off; log_not_found off; }
    }
    

    Q1 : What does the below directive mean
    fastcgi_cache_path /data1/nginx-cache1 levels=1:2 keys_zone=WORDPRESS:500m inactive=420m;

    is 500m in MBs or minutes ?what is the ideal value for it and for inactive ?

    Q2 : fastcgi_cache_valid 420m;

    What does this directive mean ? is it in MB or minutes ? what is the ideal value , Our aim is to keep the cache for many days and it should refresh only when some does a new posting .

    Q3: Is supercache in nginx better then Nginx with Fastcgi cache ? I tried varnish but had lot of problem ?

    Help will be appreciated as we have around million hits in a day and during peak loads we get very high load on Mysql and PHP-FPm process.

    Thanks ,
    Abhishek

    • Rahul Bansal

      I see many inconsistencies in your config so for config part, please refer to my post above.

      Regarding your questions:

      A1. 500m is MB (size). You can find details about parameter here

      Ideal value depends on your setup and requirement. We use inactive = 10m which is default. If load on server increases in future, we won’t mind using higher value.

      A2. 420m is minute as its duration value. You can find details about parameter here

      A3. I like nginx fastcgi-cache. Its bit complex to maintain but I enjoy using it. I am not sure about benchmarks but in theory, fastcgi-cache should perform better on large sites (1000s of cached pages)

      For any site, you can tweak things at many level. Start with http://gtmetrix.com/ and see how your site scores. Optimize by following gtmetrix.com suggestion first. Then you can move over to Nginx, PHP-FPM and also mysql-optimization.

  10. wordpress在VPS上的优化配置 « 永远的wing - wing's forever, wing's my love.

    […] Bansal 的文章配置fastcgi_cache了  http://rtcamp.com/tutorials/nginx-wordpress-fastcgi_cache-with-conditional-purging/ 。需要注意的是,如果你启用了rewrite,nginx.conf里的location /{ } […]

  11. Abhishek

    Thanks for the response , Can we cache index.php , In tutorial i can see you are not caching WordPress index.php , Will nginx nginx helper plugin work with it ?

    • Rahul Bansal

      index.php is already cached. Its URL is “/” only.

      Nginx-helper should work with it. If you find any issue, please let us know.

  12. Nginx + WordPress + Fastcgi_Cache 自动清空缓存 | 俊彦博客

    […] 本文翻译自http://rtcamp.com/tutorials/nginx-wordpress-fastcgi_cache-with-conditional-purging/ ,有修改 […]

  13. ovidiu

    I’ve got a question concerning this line: fastcgi_cache_path /var/run/nginx-cache

    What ownership/permission does that folder need to have? It seems nginx created it automatically like this:

    drwx—— 2 www-data root 4096 Jan 11 07:06 nginx-cache

    • Rahul Bansal

      @Ovidiu

      Nginx automatically creates the required cache directory.

      On our server also, we have same ownership & permissions:

      drwx—— 18 www-data root 360 Jan 9 01:38 nginx-cache

      I did not face any issue with that. Are you facing any problem with that?

      • ovidiu

        Struggling a bit but I will raise this issue on the support forum if I can’t solve it. I was just making sure that permissions and rights are not causing problems.

  14. Aahan

    @RahulBansal

    1. From your comments above, I understand that you use nginx + fastcgi_cache for this site’s page caching, which implies that cached, static versions of the dynamic pages are served by Nginx, correct?

    In that case, what’s the need for Object-Cache & Database-Cache using W3 Total Cache? The user requests don’t reach the database anyway, so, why?

    2. Is this meant for a single server setup only? or does it work just fine on a setup with multiple load-balanced servers too?

    Great job with the tutorials by the way!

    • Rahul Bansal

      @Aahan

      #1. Object-Cache & Database-Cache will speed-up “write” to cache. On a busy site where cache-needs to be flushed periodically, this may provide significant performance improvement.

      Also, on our network, we have support-forum, product-store and a community-blog. Together, they keep more than 50 users logged-in anytime. For logged-in user we do not use page-cache so object/database cache helps speed-up page-loading significantly.

      Finally, on any site, wp-admin (backend) will surely benefit from presence of object/database cache.

      #2. I haven’t tested this setup with load-balancer so this is tested with single-server setup only. Multiple load-balancers can be configured in many-ways so its hard to cover them here. Only thing I will suggest is to go with memcache in multiple-server setup.

  15. Aahan

    Oh, I missed this earlier.

    How does this kind of caching handle widgets like “Latest Posts” or “Recent Comments” in sidebar on Post pages?

    • Aahan

      Here are some examples as to what I mean:

      1. Infinite scrolling on Post pages showing the latest posts (among other things).

      2. Latest posts in sidebar with infinite scrolling.

      So, the question (again) is, how’s caching of such features handled in this method?

      • Rahul Bansal

        I am not sure how Mashable/ReadWrite guys are doing it but if you check browsers’ developer-console, you will see AJAX requests are made to fetch extra content from server.

        For example, I saw request to a URL – http://readwrite.com/_ajax/article-list?page=3&count=10 on ReadWrite.com

        I am not sure if calls to /_ajax/article-list are routed to WordPress. Assuming they are routed to WordPress, object/database-level caching will directly reduce PHP’s work.

        You can tweak Nginx config also. Basically, you can ask Nginx to cache output of PHP if request_uri starts with “/_ajax/”. Also you need to tell nginx to use fastcgi_cache even if query string is present (page, count vars in above URL).

        Make sure you adjust “fastcgi_cache_key” to include $args in Nginx config.

    • Rahul Bansal

      In our config => if browser sends a GET request (without query variable) to Nginx server, Nginx caches entire page-output it receives from PHP backend.

      Things like “Latest Posts”, “Recent Comments” etc are not known to Nginx. Its WordPress things and falls under PHP-mysql business! This is where object/database-caching kicks in. For second-page, PHP has to do less work because it can find result for “Latest Posts”, “Recent Comments”, etc in object/database-cache. For this reason, I always recommend using object/database-caching no matter which type of page-caching is being used (or even if page-cache is not used at all)

  16. Doug

    Awesome tutorial, thanks for putting it together. I’ve setup three WordPress installations under a single domain:

    mainsite.com, mainsite.com/blog1, mainsite.com/blog2

    They all serve pages correctly, however only the two WordPress installations in subdirectories correctly cache for non-logged in visitors (registered users don’t see cache ever, as expected). In other words, mainsite.com/blog1/a-random-post will serve a nginx-cached page (timestamp from half an hour ago, for example, reloading does not change timestamp), but mainsite.com/another-random-post generates a new page every time it’s accessed (timestamp updates with every reload).

    Any clue why this would be happening? Any help would be greatly appreciated.

    Here is the fastcgi part of my nginx config file:

    fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:150m inactive=180m;
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
    fastcgi_cache_use_stale error timeout invalid_header http_500;
    

    Here is my domain specific config file:

    
    server {
            listen 80;
            #listen [::]:80 default ipv6only=on;
    
            server_name www.mainsite.com mainsite.com;
            root /home/mainsite/domains/mainsite.com/public_html;
            access_log /home/mainsite/domains/mainsite.com/logs/access.log;
            error_log /home/mainsite/domains/mainsite.com/logs/error.log;
    
            index index.php index.html index.htm;
            error_page 404 /404.html;
    
            set $no_cache 0;
    
            # POST requests and urls with a query string should always go to PHP
            if ($request_method = POST) {
                    set $no_cache 1;
            }
            if ($query_string != "") {
                    set $no_cache 1;
            }
    
            # 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 $no_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 $no_cache 1;
            }
    
            location / {
                try_files $uri $uri/ /index.php$args;
            }
    
            location /blog1 {
                try_files $uri $uri/ /blog1/index.php?$args;
            }
    
            location /blog2 {
                try_files $uri $uri/ /blog2/index.php?$args;
            }
    
            location ~ .php$ {
                    try_files $uri /index.php;
                    include fastcgi_params;
                    fastcgi_pass unix:/var/run/php5-fpm-mainsite.sock;
                    fastcgi_cache_bypass $no_cache;
                    fastcgi_no_cache $no_cache;
    
                    fastcgi_cache WORDPRESS;
                    fastcgi_cache_valid  180m;
            }
    
            location ~ /purge(/.*) {
                fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
            }
    
            location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
                    access_log off; log_not_found off; expires max;
            }
    
            location = /favicon.php { access_log off; log_not_found off; }
            location = /robots.txt { access_log off; log_not_found off; }
            location ~ /\. { deny  all; access_log off; log_not_found off; }
    
    }
    

    Thanks again.

    • Rahul Bansal

      We have a similar setup like yours on our demo server.

      Rather than following…

      
             location / {
                  try_files $uri $uri/ /index.php$args;
              }
      
              location /blog1 {
                  try_files $uri $uri/ /blog1/index.php?$args;
              }
      
              location /blog2 {
                  try_files $uri $uri/ /blog2/index.php?$args;
              }
      

      We are using…

      
             set $dir "";
             
             if ($request_uri ~ ^/([^/]*)/.*$ ) {
      	       set $dir1 /$1;
             }
      
             location / {
      	       try_files $uri $uri/  $dir1/index.php?$args;
             }
      

      Try above change to see if it works!

      • Doug

        Thanks so much for your quick reply. I made the change in the domain specific config file. Unfortunately, I’m still seeing the same issue.

        In a clean browser the two WordPress installs in subdirectories, mainsite.com/blog1 and mainsite.com/blog2, run as expected, they cache correctly (create a cache file and access it on subsequent page loads). However, the WordPress install in the root directory, http://www.mainsite.com, does not cache at all. Refreshing the page results in footers like this:

        and a few seconds later:

        The WordPress install in the root directory never accesses the cache, but seems to be generating new cache files continually, whereas the WordPress installs in the subdirectories, mainsite.com/blog1 and mainsite.com/blog2, cache a page and show in the footer that they’re accessing caches from 10, 20, 60 minutes ago, etc.

        Any idea what might be happening?

        Thanks again for the help.

        • Rahul Bansal

          Try adding following line:

          fastcgi_ignore_headers Cache-Control Expires Set-Cookie

          After line:

          fastcgi_cache_use_stale error timeout invalid_header http_500;

          Do not forget to reload nginx config. Let me know if it works?

          Important: When you comment out extra lines for blogs in subdirectories, does it activates caching for main-site (in root-dir)?

          • Doug

            Try adding following line:

            fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

            Bingo! I had tried that before, I thought, but it works perfectly now.

            Thank you so much. :)

            For reference for anyone in a similar situation, here is the cache section of my working nginx.conf:

            # fastcgi cache config
            fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m inactive=180m;
            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;

            And here is the domain specific conf file:

            server {
            listen 80;
            #listen [::]:80 default ipv6only=on;

            server_name http://www.mainsite.com mainsite.com;
            root /home/mainsite/domains/mainsite.com/public_html;
            access_log /home/mainsite/domains/mainsite.com/logs/access.log;
            error_log /home/mainsite/domains/mainsite.com/logs/error.log;

            index index.php;
            error_page 404 /404.html;

            set $no_cache 0;

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

            # 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 $no_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 $no_cache 1;
            }

            set $dir “”;

            if ($request_uri ~ ^/([^/]*)/.*$ ) {
            set $dir1 /$1;
            }

            location / {
            try_files $uri $uri/ $dir1/index.php?$args;
            }

            location ~ .php$ {
            try_files $uri /index.php;
            include fastcgi_params;
            fastcgi_pass unix:/var/run/php5-fpm-mainsite.sock;
            fastcgi_cache_bypass $no_cache;
            fastcgi_no_cache $no_cache;

            fastcgi_cache WORDPRESS;
            fastcgi_cache_valid 180m;
            }

            location ~ /purge(/.*) {
            fastcgi_cache_purge WORDPRESS “$scheme$request_method$host$1″;
            }

            location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
            access_log off; log_not_found off; expires max;
            }

            location = /favicon.php { access_log off; log_not_found off; }
            location = /robots.txt { access_log off; log_not_found off; }
            location ~ /\. { deny all; access_log off; log_not_found off; }

            }

          • Rahul Bansal

            Glad to know that your problem is solved. :-)

  17. abdussamad

    Its better if access to the purge URL is limited to localhost only:

    location ~ /purge(/.*) {
    	allow 127.0.0.1;
    	deny all;
    	    fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
    	}	
    
    • Rahul Bansal

      You can restrict it if you want but purging a cache won’t do any harm apart from wasting some CPU cycles.

      This unrestricted purge comes handy when a member of our team want to see his changes immediately. We have a big team working on different parts of this site. So whenever a dev working on http://rtcamp.com/store/ want to force cache-invalidation for store only, then can simply open http://rtcamp.com/purge/store/ in browser.

      • abdussamad

        Give your team members SSH access and they can purge the cache using wget or curl.

        Anyway one reason why the purge should be restricted is that the page Nginx displays in response to a purge contains the full path of your cache. It’s better not to reveal this information to outsiders.

        • Rahul Bansal

          Thanks for your suggestion but I still prefer /purge/ via browser. I have no energy to teach everyone SSH, etc specially for something so trivial as cache-purge.

          At the max, I will consider allowing direct-purges from our office-IP address. All machine’s gets same public-IP so that will be easy.

          About full-paths… Nginx cache dir is not web-accessibles so unless someone gets into server, they won’t be able to do anything with cache-dir directly. In this case, I will focus more on hardening server so that a hacker won’t be able to log into server in the first place!

          Please let me know if there is any serious known threat we can be subjected to just by exposing cache-dir location.

        • ovidiu

          so opening an URL like this is supposed to purge? I get a 404 error => exclusive-jumping.co.za/purge/gallery/

          any ideas?

  18. abdussamad

    Another point, keys_zone in fastcgi_cache_path specifies how much shared memory is going to be used to store meta data about the cache. The point being that it is memory not disk space. So setting it to 500MB or something high like that is asking for trouble. The example given on the nginx wiki is a much more realistic 10MB.

    If you want to restrict the maximum amount of disk space that the cache takes you have to use the max_size parameter.

    • Rahul Bansal

      We have 32GB RAM! So 500MB is too less here. In fact, its 1.5625% of all available RAM. ;-)

      You are free to use whatever values you wish. :-)

      • abdussamad

        That may be the case for you but a lot of people using Nginx are on a low end VPS and they are using Nginx primarily to save memory.

        • Rahul Bansal

          That is the point! People can modify their config. In fact, they need to modify atleast domain name from example.com to their own domain.

          I will prefer to have values that we use on our client sites so that we can speed-up our client work. Most of our clients use more than 16GB RAM so 500MB cache is still very much practical.

          Another thing – rather than using VPS, you can go for dedicated servers from http://servercraft.co/dedicated-servers/. There are few more companies, which offer 4GB RAM for $49 and 8GB for $85. If you on Nginx, its better to go for such offerings IMHO.

  19. Tharindu

    Thanks for great tutorials. Is it possible to setup Varnish on top of Nginx? I would love see you doing a post about it.

  20. ovidiu

    Can you explain the reason why you don’t cache urls with a query string?
    Just being curios :-)

    POST requests and urls with a query string should always go to PHP

    • Rahul Bansal

      POST requests and urls with a query string should always go to PHP

      I think it depends on application and few other things. Sometime, query strings are unique so they generate unique results.

      Rather than disabling cache for query_strings altogether, we use mix of conditions to decide which query strings to be cached.

      You may find this discussion related -> http://rtcamp.com/support/topic/cache-urls-which-use-only-javascript-related-queries/

      • ovidiu

        Ok, thanks, I’ve read that discussion and I understand but would you mind sharing some more tips from the way you are tweaking your caching? clearly this how-to here is kept “safe” for most people hence no caching of anything query related.

  21. ylluminate

    What do you suggest when you are running new repos that provides nginx-common @ ver 1.2.7-0ubuntu0ppa1~precise vs ver = 1.2.4-1ppa4~precise that Brian’s ppa provides? I’d prefer to stick with prerolled tested debs rather than compiling at each ver update.

  22. Lauris

    Hello, ran into smalll problem :)

    W: Failed to fetch ppa.launchpad. net/brianmercer/nginx/ubuntu/dists/quantal/main/source/Sources 404 Not Found

    W: Failed to fetch http://ppa.launchpad.net/brianmercer/nginx/ubuntu/dists/quantal/main/binary-amd64/Packages 404 Not Found

    E: Some index files failed to download. They have been ignored, or old ones used instead.

    Is there alternatives?
    Thank you!

  23. Antonio

    Rahul, my ubuntu server version is quantal, can i use this ngx_cache_purge by FRICKLE with Nginx helper plugin ? How to can i install the nginx-custom on my server? My nginx version is 1.2.7.
    Thanks ;D

  24. skidnew

    hello Rahul
    My nginx version is 1.2.7 i follow your guidance above, but i can not install nginx-custom.
    if I see from https://launchpad.net/~brianmercer/+archive/nginx it states as follow:
    PPA description
    nginx_1.2.4 for 12.04 (precise).

    so, what can i do???

  25. Arick

    My site was hosted in Virtual Private Server using Nginx in front of Apache (so it has Apache previously installed, NginX was used as reverse Proxy) along with SuPHP. I came here referred by WordPress Plugin NginX helper. Am I need that plugin or I can safely run my WordPress blog without it? I’m new to VPS so kindly suggest me with the plugin.
    Thanks

  26. Jon

    You have a crucial typo: nginx -V 2>&1 | grep nginx-cache-purge -o

    No one will find the module if it’s mispelled.

    Should be: nginx -V 2>&1 | grep ngx-cache-purge -o

    • Rahul Bansal

      @Jon

      That is not typo. Its correct on Ubuntu (atleast).

      When you run nginx -V

      You get following output:

      nginx version: nginx/1.2.4
      TLS SNI support enabled
      configure arguments: --prefix=/etc/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-log-path=/var/log/nginx/access.log --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --with-debug --with-http_addition_module --with-http_geoip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_realip_module --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module --with-http_xslt_module --with-ipv6 --with-sha1=/usr/include/openssl --with-md5=/usr/include/openssl --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --add-module=/build/buildd/nginx-1.2.4/debian/modules/nginx-auth-pam --add-module=/build/buildd/nginx-1.2.4/debian/modules/nginx-echo --add-module=/build/buildd/nginx-1.2.4/debian/modules/nginx-upstream-fair --add-module=/build/buildd/nginx-1.2.4/debian/modules/**nginx-cache-purge** --add-module=/build/buildd/nginx-1.2.4/debian/modules/nginx-upload-progress --add-module=/build/buildd/nginx-1.2.4/debian/modules/headers-more-nginx-module
      
  27. 雨宫优子

    Hello.I used below configuration but it seems fastcgi_cache_bypass not work.

    fastcgi_cache_path /dev/shm/nginx-cache levels=1:2 keys_zone=WORDPRESS:500m inactive=60m;
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
    fastcgi_cache_use_stale error timeout invalid_header http_500;

    set $skip_cache 0;
    #set $cache_uri $request_uri;
    if ($request_method = POST) {
    #set $cache_uri 'null cache';
    set $skip_cache 1;
    }
    if ($query_string != "") {
    #set $cache_uri 'null cache';
    set $skip_cache 1;
    }
    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';
    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_logged_in|w3tc_logged_out|wptouch_switch_toggle") {
    #set $cache_uri 'null cache';
    set $skip_cache 1;
    }
    location ~ /purge(/.*) {
    fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
    }
    location / {
    try_files $uri $uri/ /index.php?$args;
    }

    location ~ .*\.(php|php5)?$
    {
    try_files $uri =404;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
    fastcgi_cache WORDPRESS;
    fastcgi_cache_valid 60m;
    fastcgi_pass unix:/tmp/php-cgi.sock;
    fastcgi_index index.php;
    include fcgi.conf;
    }

    The problem is,if a visitor access a page[e.g.post or index] and generate this page cache,logged in user will unexpected get this page cache.Luckily the nginx isn’t generate page cache from logged in user.

    So it seems fastcgi_cache_bypass not work.But i checked this configuration and NginX-wiki number of times.Everything looks correct.

    Server Environment:

    NginX 1.2.8[complied –with-http_ssl_module –with-http_gzip_static_module –with-ipv6 –add-module=../ngx_cache_purge-master]

    PHP 5.3.23 FPM-FCGI

    CentOS 5.9

  28. Nginx + WordPress + Fastcgi_Cache 自动清空缓存 - VPS间谍

    […] 本文翻译自http://rtcamp.com/tutorials/nginx-wordpress-fastcgi_cache-with-conditional-purging/ ,有修改 […]

  29. Rahul Bansal

    closed keepalive connection is something you no need to worry about.

    May be you can try using our free support forum here – https://rtcamp.com/support/forum/wordpress-nginx/

    We can try to debug it there in-depth.

  30. Akshay Raje

    At an overall level, what would you recommend between fastcgi_cache vs page caching using W3 Total Cache? Does it depend on volume of traffic?

    Mine is not a MU set-up and I don’t have data on traffic as the project is not live yet.

    • Rahul Bansal

      I like fastcgi_cache as I am more comfortable playing with Nginx.

      In terms of traffic, there shouldn’t be much difference. Once a page gets cached, a proper configuration will always use Nginx alone to serve cached page.

      If your MU was created before WordPress 3.5, then this article can make a lot of difference – http://rtcamp.com/tutorials/nginx-map-wordpress-multisite-static-files-handling/

      • Akshay Raje

        How about using Memcached for page caching? Somehow am not very comfortable in making disk calls too often for caching.

        Btw, I am on Amazon EC2 and planning to use Memcached like this – http://www.kingletas.com/2012/08/full-page-cache-with-nginx-and-memcache.html. Whats your take?

        • Rahul Bansal

          For memcache, you will need a plugin on WordPress side to create cached version of page. Nginx can only read from memcached.

          For disk I/O issue, I am already using tmpfs (RAMDisk). I already mentioned about it in above article. ;-)

          By the way, even if you use disk based caching, as long as you have enough free memory, OS will cache static html pages in-memory like it caches any frequently accessed items.

  31. Abhishek Sharma

    Hi Rahul ,

    It seems loop-page-home.php is not getting cached ….

  32. pdflog

    Add extra header for browser cache

    if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/page/|/feed|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
    	expires epoch;
    	add_header Cache-Control "no-cache, no-store, must-revalidate, max-age=0";
    	add_header pragma no-cache;
    	add_header Last-Modified "";
    	set $skip_cache 1;
    	}
    
    • Rahul Bansal

      First, we are not suppose to cache output of backend php scripts. If we do so, user-2 may see dashboard view of user-1 and so on!

      Second, it you want to force caching use expires max.
      expires epoch is used to disable caching.

  33. pdflog

    Yes, i meant not to cache to browser side using expires epoch; and add_header Cache-Control “no-cache, no-store, must-revalidate, max-age=0″; and not to cache on nginx cache set $skip_cache 1;
    Actualy i’m not implemented nginx cache for my heavy traffic website because i’m using varnish to cached it. Nginx is too complicated to purge cache but varnish is more simple.

  34. Jinn Ko

    On Debian wheezy there are multiple available builds of nginx. To install the build that contains the nginx-cache-purge module aptitude install nginx-naxsi.

    • ovidiu

      I once found a link comparing the different nginx packages available but can’t find it anymore – does anyone else have an overview like that so that we can see which nginx package contains what modules?

    • RavanH

      nginx-naxsi is also available in the ubuntu repos… is there any reason not to use it?

      • Rahul Bansal

        We haven’t used nginx-naxsi yet. Though its on list. Once we test it, we will cover it in another tutorial.

        • RavanH

          Hi Rahul, as far as I can figure out, it’s more like nginx-light plus Naxsi firewall and Cache Purge… Which might not be enough for some but in our case, since we’re not going to offer any other services like mail boxes or ftp for our users (just a site running on WPMS) I have the impression it will serve us well. I’ll be testing this the coming week anyway :)

          Anotherquestion: I hade prepared a VPS with Debian 7 before coming here and I’m wondering if there is any other reason to start fresh with Ubuntu other than that Debian does not have a tmpfs mounted on /var/run/ by default. What would you advise?

        • RavanH

          OK, after setting up two Debian Wheezy VPSes with nginx-naxsi (so no need for any PPA’s since Wheezy has PHP 5.4 too) I can say it works smoothly. Following your excellent tutorials, there are no differences, appart from fore-mentioned.

          Only thing I notice is that df -h /var/run reports a 10% of RAM size. Which seems logical since tmpfs has a RUN_SIZE=10% default. At least in Debian Wheezy… This value can be changed in /etc/default/tmpfs but I’m not sure what to do here. What would you advise as min or max space for the FastCGI cache?

          Thanks!

          • Rahul Bansal

            Sorry for late reply. As article list is growing, its becoming hard to track which comments without replies! :|

            About your questions:
            1. Debian/Ubuntu – I guess not much difference at our level. Ubuntu choice is matter of personal taste. I think on Debian also you found out tmpfs.
            2. fastcgi-cache size – there is no min-max. Start with a random size and monitor size of fastcgi-cache folder after few days. If its full, increase it as long as your RAM permits.

            I believe that max-size you specify is size allowed for storage. If you have no cached files, no space from tmpfs will be used for fastcgi-cache.

          • RavanH

            Hey Rahul, no problem I completely understand. Threaded comments are not very easy to manage and keep up. Maybe the forum section in this site is better suited for these kinds of discussions ;)

  35. Jinn Ko

    I found that nginx-naxsi has the necessary module while in the process of recompiling nginx from debian sources. After that I discovered the modules are listed in the package descriptions themselves:

    http://packages.debian.org/wheezy/nginx-light
    http://packages.debian.org/wheezy/nginx-extras
    http://packages.debian.org/wheezy/nginx-full
    http://packages.debian.org/wheezy/nginx-naxsi

    • ovidiu

      Thanks for that but do you have any idea what this means: “OPTIONAL HTTP MODULES”? AFAIK nginx isn’t modular so what does optional mean in this case?

      • Rahul Bansal

        nginx-light, nginx-full etc are pre-compiled packages with different modules.

        Its like “combo-meals” we see in restaurants. Different packages has different set of modules. If you do not like any package at all, you can compile nginx with own list of modules.

        So IMHO nginx is modular at compile time! ;-)

  36. hansa

    Hi,
    try to install on Ubuntu ,I am getting this error
    “E: Unable to locate package nginx-custom”.

    as requested from command – apt-cache showpkg nginx

    Package: nginx
    Versions:
    1.2.1-2.2ubuntu0.1 (/var/lib/apt/lists/us.archive.ubuntu.com_ubuntu_dists_quantal-updates_universe_binary-amd64_Packages) (/var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_quantal-security_universe_binary-amd64_Packages)
    Description Language:
    File: /var/lib/apt/lists/us.archive.ubuntu.com_ubuntu_dists_quantal_universe_binary-amd64_Packages
    MD5: 19a4ea43e33eae4a46abf8a78966deb5
    Description Language: en
    File: /var/lib/apt/lists/us.archive.ubuntu.com_ubuntu_dists_quantal_universe_i18n_Translation-en
    MD5: 19a4ea43e33eae4a46abf8a78966deb5

    1.2.1-2.2 (/var/lib/apt/lists/us.archive.ubuntu.com_ubuntu_dists_quantal_universe_binary-amd64_Packages) (/var/lib/dpkg/status)
    Description Language:
    File: /var/lib/apt/lists/us.archive.ubuntu.com_ubuntu_dists_quantal_universe_binary-amd64_Packages
    MD5: 19a4ea43e33eae4a46abf8a78966deb5
    Description Language: en
    File: /var/lib/apt/lists/us.archive.ubuntu.com_ubuntu_dists_quantal_universe_i18n_Translation-en
    MD5: 19a4ea43e33eae4a46abf8a78966deb5

    Reverse Depends:
    nginx-common,nginx 0.8.54-4
    nginx-common,nginx 0.8.54-4
    puppetmaster-common,nginx
    samizdat,nginx
    php5-midgard2,nginx
    nginx-common,nginx 0.8.54-4
    nginx-common,nginx 0.8.54-4
    fcgiwrap,nginx
    collectd-core,nginx
    cardstories,nginx
    cacti,nginx
    puppetmaster-common,nginx
    Dependencies:
    1.2.1-2.2ubuntu0.1 – nginx-full (16 (null)) nginx-light (0 (null))
    1.2.1-2.2 – nginx-full (16 (null)) nginx-light (0 (null))
    Provides:
    1.2.1-2.2ubuntu0.1 –
    1.2.1-2.2 –
    Reverse Provides:
    nginx-naxsi-ui 1.2.1-2.2ubuntu0.1
    nginx-naxsi 1.2.1-2.2ubuntu0.1
    nginx-light 1.2.1-2.2ubuntu0.1
    nginx-full 1.2.1-2.2ubuntu0.1
    nginx-extras 1.2.1-2.2ubuntu0.1
    nginx-naxsi-ui 1.2.1-2.2
    nginx-naxsi 1.2.1-2.2
    nginx-light 1.2.1-2.2
    nginx-full 1.2.1-2.2

    nginx-extras 1.2.1-2.2

    Please help.
    Thanks.

    • Rahul Bansal

      Did u add ppa:brianmercer/nginx? Your Nginx is old (1.2). Current series is 1.4.x

      What version of Ubuntu you are using?

  37. hansa

    Hi,
    Thanks for reply.i am using Ubuntu 12.10.

    • Rahul Bansal

      You need to check files in /etc/apt/sources.list.dand content of file /etc/apt/sources.list.

      It might be case you have added another Nginx repo from elsewhere. Some cheap hosting companies bundle OS templates with their local mirror which are not synced with official repos in timely manner.

      Finally, did you run apt-get update? This is surely repo issue.

  38. hansa

    Yes i ran apt-get update.Just now i have Updated my Nginx.Now it is showing 1.4.1.
    Please help me to get Purge Module.
    Thanks.

  39. hansa

    One more update when i ran apt-get update

    i found 404 errors at the end.

    W: Failed to fetch ppa.launchpad.net/brianmercer/nginx/ubuntu/dists/quantal/main/source/Sources 404 Not Found

    W: Failed to fetch ppa.launchpad. net/brianmercer/nginx/ubuntu/dists/quantal/main/binary-amd64/ Packages 404 Not Found

    W: Failed to fetch ppa.launchpad.net/brianmercer/nginx/ubuntu/dists/quantal/main/binary-i386/P ackages 404 Not Found

    E: Some index files failed to download. They have been ignored, or old ones used instead.

  40. WordPress Plugins for the NginX Web Server

    […] Appearing in the repository as just “Nginx” (which I hope the author soon fixes), this is a plugin I won’t use unless I decide to use the NginX FastCGI Cache with conditional purging. […]

  41. Jim

    Nice tutorial!
    My nginx server is already running on Ubuntu 12.04. Now I’m going to upgrade nginx with the purge module. The problem:

    Is it safe to upgrade from the ppa?
    Does upgrading process erase previous configurations?

    • Rahul Bansal

      @Jim

      There is no issue in upgrading PPA. As a habit, I always backup config files. e.g. /etc/nginx

      In case of conflict you may need to remove old packages first by using apt-get remove

  42. Tamara

    Hi,

    First of all thank you so much for the tutorial and the wonderful plugin! I followed it and everything is working wonderfully.
    I’ve noticed that when I want to do a manual purge by visiting mydomain/purge I get directed to a “Successful purge” message which is nice. However, it shows the cache path on my server and my nginx version. I have successfully hid my nginx version using server_tokens off but it still seems to show up on this page. I’d also like to hide the cache path if at all possible.

    Thank you for your help,
    Tamara

  43. Jinn Ko

    @Tamara, very good observation. You’ll need to open a ticket with the maintainer to address these issues correctly. Going through the official nginx wiki it looks like the place to do that is via http://labs.frickle.com/nginx_ngx_cache_purge/.

  44. Rahul Bansal

    @Tamara & @Jin

    We use allow/deny directives for this. It goes like:

    location ~ /purge(/.*) {
    	    fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
                allow 127.0.0.1;
                allow 1.2.3.4; #replace with your static-ip
                deny all;
    	}

    Make sure you replace 1.2.3.4 with your own static-IP. Also leave 127.0.0.1 as it is for Nginx-helper.

  45. Tamara

    @Jinn
    Thank you for the link. I poked around the GitHub repo a bit and it looks like it hasn’t been active for a few months. I might file an issue here to see if there are other options so I can better accommodate the team as well.
    @Rahul
    Thank you! This is sufficient for now but it would be great if there was another way so I will report back if I ever find anything. Thanks again for the wonderful work you and your team are doing.

    • Rahul Bansal

      @Tamara

      I think the allow/deny way is recommended way. Most likely plugin author will tell you the same.

  46. ovidiu

    Just wondering if it is correct that these two lines are not exactly the same?

    `fastcgi_cache_key “$scheme$request_method$host$request_uri”;`
    vs.
    `fastcgi_cache_purge WORDPRESS “$scheme$request_method$host$1″;`

  47. Rahul Bansal

    Yep. They are correct.

    In purge block, $request_uri contains “/purge” at the beginning for every cached page-url. So $1 variable captures correct cached-url (without “/purge” in the beginning).

  48. Gagan

    About the lines

    # 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)")
    

    Can’t we skip the part “wp-(app|cron|login|register|mail).php” as its already covered by “wp-.*.php” and the same goes for all the patterns starting with “wp-“? Wouldn’t it be more efficient since there would be less number of comparisons?

    • Rahul Bansal

      Yep. They are redundant. Also some more checks can be removed like wp-admin is redundant because of cookie-check.
      wp-.*php will also match wp-comments-popup.php, wp-links-opml.php and wp-locations.php

      I will refactor config soon as such a change need to be propagated to many other articles in this series.

      Thanks for pointing it out.

  49. Abdoul BAH

    Hi,
    I fastcgi_cache configured as shown for my WP, everything is OK, but I find that the number of views of the pages is distorted.

    Do you know where this is from? I use WP_VIEWS and each refresh must be considered view.

    Best regards,

    • Rahul Bansal

      I am not sure how your view counting plugin is working but any stats codes in PHP won’t work for cached pages.

      In fact that is goal of caching. You can use javascript-based stats tool like Google Analytics or a wordpress plugin which uses JS-based counting.

    • Abdelkader Boudih

      You can parse your nginx access log file for accurate data.

      Best regards

  50. Abdoul BAH

    Thank you for this answer.

    I have another problem. I use two web loabalancing via keepalive server. I have no problem with memecache but the fastcgi cache being not share some part of the site is not displayed correctly on one server. Is that in the state ngixn-helper plugin purge on all front? is it possible to set this?

  51. Jesin

    Is it possible to prime/preload cache in nginx just like how W3 Total Cache offers an option to do it?

  52. buzz

    Hello,

    I found many instances of the follwoign error on my nginx helper log file. How do I correct this?:

    2013-09-27 23:56:37 | ERROR | Error while purging URL. SSL certificate problem: self signed certificate

    Thank you,

    buzz

    • Rahul Bansal

      It looks like you are using a self-signed SSL.

      We will try to debug this. Most likely this is coming from low-level curl function.

  53. Guill

    Hi,

    Just wondering, because I get lost with all these caches options. I have a server running nginx, php-fpm, php5.5 and the zend optimizer. The zend optimizer should cache pages already right? So is there a point to ask nginx to cache? If yes, then should I remove the zend optimizer or keep it along? Also, I read about page cache and data cache and opcache and blablacache so I’m not sure, do I still need something like WP or W3 for caching something else? I’m new to wordpress, I’ve followed some of your very useful tuts, but I’m still slightly lost. Thanks

    • Rahul Bansal

      zend opcache, caches PHP code only. Its very low-level caching and speed-up raw PHP code execution.

      w3tc needs a data-cache backend for mysql-cache and object-cache. You can use memcache for this – http://rtcamp.com/tutorials/php/memcache/

      zend opcache and memcache can speed up page-cache generation as well as speed up backend site.

      You finally need a full-page-caching where nginx-fastcgi is an option to reduce load on backend for page-requests which doesn’t change much over time.

      • Guill

        Thank you Rahul!
        I actually got that trough your articles. Very nice!

        • Guill

          I’m finding an issue though on my site and I think it’s cache related.
          If I don’t visit the site for a couple of days, the next time I visit any page I get a 500. If I reload the page shows up, very fast, so I think it’s been cached at the first request, the one that returned the 500. But I still receive a 500 first. Nginx error log shows nothing, the access log shows the 500 but nothing more. I can’t find where is the issue from, I guess php5-fpm but no error in log either. Any idea where I can look for more?

  54. Guill

    After reading a lot, I think I got it.
    Also, I’ve added CSS and JS to the list of file types to force the expires max statement. If not there, if php5-fpm breaks, the page will be loaded but without the CSS and the JS. Does it make sense?

    • Rahul Bansal

      Do not add js and css directly to expire-max block.

      Many things can go wrong for dynamically generated JS and CSS files. Also, browser-may cache JS/CSS changes longer than expected!

      • Guill

        Yeah I see, it makes sense.
        But if there is no location block for js/css, it will go through the ~ .php$ block and breaks. So I should just add an empty location for js/css, shouldn’t I?

  55. rpns

    First of all, thank you for both this manual and Nginx-helper!

    Does one really need to check whether ($request_method = POST), for there is an Nginx directive fastcgi_cache_methods?

    • Rahul Bansal

      Nice catch!

      Actually, nginx fastcgi-cache by default does not cache any HTTP-POST request in first place.

      I will check if there is any side-effect of removing ($request_method = POST).

      Refactoring this config is on my TODO list from long time.

  56. Nicholas O.

    Rahul,

    I got a question. So I have LEMP + Single-Site WordPress. I created a sub-domain on my server to host static files (cookie free domain). It’s pointed to the same root folder of my domain. I can’t seem to get images on my site to load properly.

    for the subdomain:

    server {
            listen          80;
            server_name     cdn.mydomain.com;
            root            /var/www/mydomain/htdocs;
    
            location ~* \.(?:js|css|ogg|ogv|wav|mp4|jpg|jpeg|gif|png|ico)$ {
                    expires max; log_not_found off; add_header Pragma public;
                    add_header Cache-Control "public"; access_log off; break;
            }
    
            location / {
                    return 404;
            }
    }
    

    for my main domain:

            location ~* \.(?:js|css|ogg|ogv|wav|mp4|jpg|jpeg|gif|png|ico)$ {
            if ($http_referer ~ "wp-admin") {
                    break;
            }
            if ($request_filename ~* jquery\.js$) {
                    break;
            }
                    return 404;
            }
    

    Any thought on what I need to do so wordpress will read from my cdn.mydomain.com/wp-content… wp-includes folders?

    Also notice my site is broken as soon as I place js|css in the subdomain code.

    • Rahul Bansal

      Please use support forum for such requests – http://rtcamp.com/groups/wordpress-nginx/forum/

      Anyway, in your case, try removing location block with file-extensions. You are using too many if conditions which can create problem.

      Lastly, I will recommend not to take cookie-free domain suggestion too seriously. Considering size of static assets, cookie overhead is negligibly small. It’s better to use external CDN (in case optimization is goal).

  57. Jesin

    Let’s forget about WordPress here. How does one manually purge the cache if the nginx-cache-purge isn’t installed?

    • Abdelkader Boudih

      You visit the /purge/ link.
      Eq : http://localhost/purge/posts.php will purge the cached posts.php
      You should restrict who can purge your cache.

      • Jesin

        Thanks for the quick reply. But that happens only if I compile nginx with the nginx-cache-purge module or install nginx-custom via brianmercer repo right?

        • Abdelkader Boudih

          Yes. you also have to add

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

          You can change ~ /purge(/.*) to anything you want : ~ /mytopsecretpurgepath(/.*)

          There is also possibility to purge the cache from the server side by deleting the cache file. You won’t need the ngx-cache-purge module then.

  58. A.Eriksson

    Hello! I followed your guide but I keep getting following error:

    2013/10/23 04:47:15 [crit] 2160#0: *4 connect() to unix:/var/run/php5-fpm.sock failed (2: No such file or directory) while connecting to upstream…

    Any suggestions on how to solve this?

    • Rahul Bansal

      Looks like your PHP-FPM is listening on TCP/IP socket.

      Change fastcgi_pass value to 127.0.0.1:9000

      If this also fails to work, open /etc/php5/fpm folder and check value for listen directive.

  59. August E

    Thank you! It is working just fine now. But I noticed that rt-Fastcgi-Cache always reports MISS the first time a page is loaded. After that it reports HIT. Is this due to the size of fastcgi_buffers and fastcgi_buffer_size?

    Currently I’m using this:

    fastcgi_intercept_errors on;
    fastcgi_ignore_client_abort off;
    fastcgi_connect_timeout 60;
    fastcgi_send_timeout 180;
    fastcgi_read_timeout 180;
    fastcgi_buffer_size 32k;
    fastcgi_buffers 16 32k;
    fastcgi_busy_buffers_size 256k;
    fastcgi_temp_file_write_size 256k;

    Should I change some values?

    • Rahul Bansal

      Above parameters has nothing to do with fastcgi caching.

      First time MISS is evident of-course as a page need to be cached when cache is fresh. After that for subsequent requests HIT should be returned.

      • August E

        Thank you for your reply. I think I got my installation working but I’m still confused by the fact that the cache seems to purge itself. For example:

        a) I visit one page 20.01 and it receives a html time stamp with that time.
        b) For a while this time stamp is showing the same time when visit the same page (as it should)
        c) But if I come back to the page after say 30-60 min, the old time stamp is not showing. I will then get a new time stamp. During this time no new page/post/comments were published.

        What should I look for in my conf files if this is due to a malfunction?

        • Abdelkader Boudih

          If you copied the configuration from the tutorial, your cache will be valid for 1h.
          You can increase that by changing fastcgi_cache_valid .

  60. Gaurav

    When I try this and restart nginx, I get this error

    Restarting nginx: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: [alert] mmap(MAP_ANON|MAP_SHARED, 524288000) failed (12: Cannot allocate memory)
    nginx: configuration file /etc/nginx/nginx.conf test failed
  61. August E

    Another question: is it totally redundant to use fastcgi_cache and a wordpress plugin such as WP-SuperCache?

  62. waseem

    i dont know how to enable wordpress perma links in wordpress as i installed wordress on subdomain. and i am using direct admin control panel, there is no site-available directory on etc/nginx.
    i dont know how to tackle this i am using centos as my OS.

    Please help
    Regards

  63. WordPress Plugins for the NginX Web Server

    […] Appearing in the repository as just “Nginx” (which I hope the author soon fixes), this is a plugin I won’t use unless I decide to use the NginX FastCGI Cache with conditional purging. […]

  64. Jon

    Is there anyway to enable the fastcgi_cache_purge module on an existing nginx install where I can’t uninstall and build from source?

  65. Transition to LEMP – Andrew Ferguson dot NET

    […] rtCamp has a really great tutorial on setting up fastcgi_cache_purge that allows Nginx to cache WordPress data and then purge and rebuild the cached content after you edit a post/page from WordPress dashboard or approve a comment on an article. […]

  66. Doug

    I’ve done this setup and all is well, except for one rather large issue. I’m running php-fpm as “myuser” (different user for each site). The nginx fastcgi_cache is owned by www-data (the nginx user). So cache purging in the WordPress module doesn’t work — permission denied.

    • Rahul Bansal

      You can add PHP user to Nginx user group and then chmod nginx cache location to `0775` so that group users can delete content.

      Please let me know if this works for you.

      • Doug

        Thanks Rahul, but this doesn’t resolve it. I get permission denied on subdirectories created in the cache by nginx:

        2013/12/11 08:28:06 [error] 12879#0: *574 FastCGI sent in stderr: “PHP message: PHP Warning: opendir(/var/run/nginx/cache/trapline/a): failed to open dir: Permission denied in /home/trapline/public_html/wp-content/plugins/nginx-helper/purger.php on line 686

        Nginx doesn’t assign any group permissions on subdirectories and files inside the cache:

        [root@bfl3:/var/run/nginx/cache/trapline] ls -l
        total 12
        drwx—— 3 www-data www-data 4096 Dec 10 13:45 4

        I’ve been through the nginx docs and there doesn’t seem to be any way of changing those permissions.

        To be clear, the error only occurs when using the Purge Cache link. Regular cache management, e.g. after editing a page, works fine.

      • Doug

        One workaround I’ve found is to flatten the cache so that no subdirs are created (remove levels= from the fastcgi_cache_path definition). Then change the main cache directory ownership to myuser:www-data with permissions 770. A user can delete files regardless of file ownership as long as he/she has ownership of the containing directory.

        Of course this raises the probability of md5 collisions. http://stackoverflow.com/questions/201705/how-many-random-elements-before-md5-produces-collisions is a good read. My favourite comment:

        “There may of course be many other bad things which can happen with a probability of 1/2^128. You might not want to single-out this one to worry about.”

        • Rahul Bansal

          Thanks for sharing details.

          I think for time being you can skip worrying about collisions if this flattening is working for you.

          I also think if there is a collision, multi-level may not help as files with same has will end-up competing for same path. So I think flattening and collisions are not related.

          I think with flattening, you may need to worry about OS limit for “number of files allowed in a directory”. In practice, you may never hit this limit.
          Another side-effect might be “increase in lookup time” by few microseconds!

          • Doug

            Thanks Rahul, good points. Here’s workaround #2…

            location ~ \.php$ {
            try_files $uri /index.php;
            include fastcgi_params;
            fastcgi_cache_bypass $skip_cache;
            fastcgi_no_cache $skip_cache;
            fastcgi_cache MYUSER;
            fastcgi_cache_valid 60m;
            if ($args ~ nginx_helper_action=purge) {
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            }
            fastcgi_pass unix:/var/run/php5-fpm-myuser.sock;
            }

            php5-fpm.sock is an fpm pool with user www-data, and php5-fpm-myuser.sock is the myuser pool.

            I’ve restored multi-level caching and Purge All works, though I’m not sure this is the best way to do it in the config….

          • Rahul Bansal

            This is really innovative workaround! Never thought like this.

            I think you can use flat-system as running extra PHP-FPM pool, for sake of ownership, will waste some RAM.

            Difference of lookup would be extremely small. If system runs out of RAM and has to use virtual/swap memory, performance impact will be bigger.

            And finally, single pool will be easier to manage. :-)

  67. Simon

    Hi there,

    For some nightmarish historical reasons I’m trying to get this setup behind an apache front-end – so I’ve got 2 nginx/php servers and apache in front of them. When I hit the nginx nodes directly the cache directory is filling up, but when I use the front-end, neither of them seem to cache. Does anyone know any reason why this might be?

    Cheers,
    Si

  68. igid26

    Hello,

    I just compiled nginx with ngx_purge module. However, my system has only 1GB of RAM – which is being enough for me as I’ve been using WP Super Cache for more then 1 year. When following the nginx configuration for your tutorial, I got the result from nginx -t:

    nginx: [alert] mmap(MAP_ANON|MAP_SHARED, 524288000) failed (12: Cannot allocate memory)

    I use CentOS and have SSD instead of HD. I’d love to know how can I make nginx save cache files on disk instead of saving it on RAM. What do I have to change in the config file in order to achieve it?

    Thanks!

    • igid26

      P.S: I’ve already read a commend above that suggests changing the memory from 500m to 10m. However, may using a low number prevent caching of new files?

      The ideal configuration for me would be saving files on memory until a certain limit (ex: 100MB) than start to save them on the disk. Is there a way to do it?

      Thanks again.

      • Rahul Bansal

        If you have only 1GB RAM, I will recommend not using tmpfs.

        Just changed cache location to and disk-based path. Most frequently accessed files will be cached by OS always.

  69. igid26

    Hello Hahul,

    Thanks for answering.

    So, I can specify the cache folder to anywhere I want, for example: (/etc/path/to/somefolder), define the new folder in WP-Config to have it working with Nginx Helper. Ok. Did it. But will be the files automatically saved in RAM up to the limit I define in the keys_zone=WORDPRESS:100m?

    • Rahul Bansal

      I forgot to ask about updating cache location for nginx-helper.

      You can add a line in wp-config.php like below:

      define( 'RT_WP_NGINX_HELPER_CACHE_PATH','/var/run/nginx-cache');

      You can use any path, but I will recommend using a folder inside /tmp or /var.

      Since you are using 100m on disk, nginx cache will allow caching till 100 MB storage is used on disk. On disk you can make if 1GB as well. Once defined limit is hit, nginx will remove content from cache based on least recently used page.

      About RAM, don’t worry. Your OS will make sure that cached copy for your most-visited pages remains in memory.

      • igid26

        Hello Rahul,

        I defined files to be saved in /tmp. However, setting it to 900m results in an error:

        Starting nginx: nginx: [alert] mmap(MAP_ANON|MAP_SHARED, 943718400) failed (12: Cannot allocate memory)

  70. Arunkumar

    Hi,
    Thanks for this wonderful article. I am using ubunbu+nginx+php5-fpm and had my wordpress installed. I had the problem of my server overloading during the peak traffic hours. After trying countless changes in the different configuration settings, i realized that my cache plugin was not working, the pages were not cached at all. so i tried different cache plugins but none worked for me.. i was unable to get the timestamp in the source file.. But then i came across this site and decided to cache internally..
    i have installed the nginx-custom module and also installed the nginx helper plugin. i finally could see a timestamp at the bottom of the page but then i edit the website config file and try to restart nginx i get this error [emerg] unknown directive “fastcgi_cache_purge”

    I would be really grateful if u could help me solve my problem.. Thanks in advance

  71. igid26

    @Rahul,

    I couldn’t reply to your last comment. I get for both commands:

    # df -h
    Filesystem      Size  Used Avail Use% Mounted on
    /dev/sda         30G   14G   15G  47% /
    none            499M     0  499M   0% /dev/shm
    
    #mount
    /dev/sda on / type ext4 (rw,errors=remount-ro)
    none on /dev/shm type tmpfs (rw)
    none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
    
    • Rahul Bansal

      Do you have swap enabled?

      Command: swapon -s

      • igid26

        # swapon -s
        Filename Type Size Used Priority

      • igid26

        Rahul,

        According to what I searched in the web, I have to create a swap file. Creating it is not a problem, I’ve already found great tutoriais. However, this is the first time I’m going to do it. As I could understand, a swape is an extention to RAM, but saved in the disk.

        My question is: how can I be sure that the swap will be used for fastcgi-cache and not for nginx/php/mysql/other system processes? The procedure is just as easy as creating the swap and let the system do all the rest or do I have to care about something else?

        Thanks.

        • Rahul Bansal

          There is no harm in letting other processes use SWAP. We always keep swap enabled as it can prevent applications from crashing when memory gets full.

          We keep watch on amount of swap space being used. Ideally, it should be never used even if its enabled!

  72. R Foreman

    I’m not sure if you’re the one who is performing updates on the nginx-helper plugin, but I’ve identified a slight bug in it that prevents purging of certain pages. To fix it I added a couple lines to the purge_url function in the purger.php file, as follows (I just added the else clause)
    if ( isset( $parse[ ‘query’ ] ) && $parse[ ‘query’ ] != ” ) {
    $_url_purge .= ‘?’ . $parse[ ‘query’ ];
    } else {
    $_url_purge = trailingslashit( $_url_purge );
    }
    It seems that without the trailing slash, some pages don’t get purged (like the home-page) when comments are added/deleted in a post. Otherwise it’s a wonderful plugin. Thanks for all the effort put into this.

    • Rahul Bansal

      Thanks for update. I think wordpress enforces trailing slash. I was under impression that trailing slash will be enforced during cache purge also.

      Can you please send your change as a pull-request on https://github.com/rtCamp/nginx-helper? We will merge it, test it and release it on wordpress.org. Also, if you send pull-request, please add your wordpress.org username to contributors list.

      Thanks.

  73. igid26

    Rahul,

    Regarding my last comment, if I have 1GB of RAM being used by MySQL/PHP/nginx. I will create a 1GB swap. How can I be certain it will not slow down PHP and MySQL and be used just for what really need it to be used (in that case, specifically for fastcgi cache)?

    • igid26

      Just to be clear, I enabled swipe and it’s work. I just have this doubt I have. One more thing: congratulations for the attention you give to rtCamp’s readers. I realized you reply every single comment while surfacing on old comments in this page. This is not something we are used to see in many blogs or foruns. :)

    • Rahul Bansal

      I think, we cannot control which apps will start using swap, once swap is available.

      There are some kernel parameters you can tweak to reduce swap usage. See – https://rtcamp.com/tutorials/linux/sysctl-conf/

  74. Doug

    One unfortunate thing I see is that all benefit of the fastcgi cache is lost for users who have commented anywhere on a site. WordPress sets a long-lived “comment-author” cookie, and if that cookie is present then the cache is bypassed. As I’ve left comments here before I see:

    rt-Fastcgi-Cache: BYPASS

    …for ALL pages on this site (using the Live HTTP Headers plugin for Firefox).

    The only solution I guess is to reduce the lifetime for the comment-author cookies. This means that commentors have to retype their name & email more frequently, though browser completion helps with that.

    • Rahul Bansal

      You can ignore comment-author cookie, if you want to show cached version of pages to commentors.
      It might confuse them as non-cached version shows “Your comment is awaiting moderation” message.

      • Doug

        Agreed, moderated commenting is confusing without the cookie. A compromise I think is to set the cookie timeout to a very low value, e.g. 1 minute, and modify CSS for the comment moderation message so it is bold and highlighted.

        – A comment is posted and the cookie is set;
        – Page is reloaded and user sees highlighted message;
        – Cookie expires in one minute and user is back to browsing cached pages.

        So the message essentially works as a one-time notification. Might also edit the message text to be a bit more descriptive…

        • Rahul Bansal

          Cookie duration change might affect usability as user will have to type email, name & site info again.

          I think client side JS can be used to detect cookie and add “awaiting moderation”.

          We might such a solution in http://wordpress.org/plugins/nginx-helper/ (github link) plugin in future subject to feasibility! There are very high chances that something else might go wrong.

          If you manage to find a suitable workaround, please share.

          On side-note, from long-time I want to AJAXify wordpress comment submission. In AJAX case, we can show “moderation” message on successful comment submission. After page-reload/revisit “moderation” message may disappear (assuming comment-cookie is ignored), but it will avoid confusion somewhat in my opinion.

  75. sectio aurea » Speed! Moaar Speed! – WordPress mit Nginx + fastcgi_cache + optional Domain Mapping

    […] dieser Anleitung sind natürlich gerne gesehen. Für weitere Informationen kann ich auch noch dieses und dieses und dieses und dieses Tutorial empfehlen, auf diesen basiert in weiten Teilen meine […]

  76. David Rahrer

    I had to remove the second “(” in the directive under the heading “# Don’t cache uris containing the following segments.” Before I did, I was getting errors “nginx: [emerg] pcre_compile() failed: missing ) in…” The only thing that bothers me is that I can’t find that mentioned in all these comments. Am I missing something?

    Outstanding resource you have here – thank you!

    • Rahul Bansal

      Thanks for your feedback. :-)

      During my last edit, I forgot to add a closing “)” in that line. Removing second “(” is fine as well. Since it was no longer required, I removed that as well from above article.

  77. 13 Things to Expect When Setting Up Unmanaged Hosting | Little Bits of Stuff

    […] package with limited CPU and RAM. Be careful about choosing a page caching WordPress plugin. Nginx Helper does everything you need without many bangs and whistles. I also ran into a package called php-apc […]

  78. panda

    @RahulBansal

    After followed your great tutorial, my nginx site with purge module works great!

    But recently I got a problem to do with the Cache: both site pages and wp-login are loading endlessly with blank pages which says “waiting for cache…” and I need to restart Ubuntu Server to fix it. And I was always getting 500 server error when deleting large mount of spam comments or publishing a new post.

    I’ve checked the log, php5-fpm log is OK, nginx error log “connection reset by peer” when publishing a new post. Memory usage is OK. Single php5-fpm uses 10 ~ 50 CPU!!.

    My cache settings looks like this:

    “fastcgi_cache_patch /var/log/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m incative=60m;
    fastcgi_cache_key “$scheme$request_method$host$request_uri”;
    fastcgi_cache_use_stale error timeout invalid_header http_500;”

    Do I need to change something to make it running with my personal blogs (1GB vps, 10K+ traffics)?

    Thanks!

    • Rahul Bansal

      Can you try replacing line – fastcgi_cache_use_stale error timeout invalid_header http_500;

      with line – fastcgi_cache_use_stale updating error timeout invalid_header http_500 http_503;

      Don’t forget to reload nginx config.

      If above workaround doesn’t fixes your issue, please create a support request in our free forum – https://rtcamp.com/support/forum/wordpress-nginx/ and make sure it includes your sites’ complete nginx config and error log.

  79. 13 Things to Expect With Unmanaged Hosting - All The Little Bits

    […] package with limited CPU and RAM. Be careful about choosing a page caching WordPress plugin. Nginx Helper does everything you need without many bangs and whistles. I also ran into a package called php-apc […]

  80. Tony Perez

    Thanks for an excellent tutorial! I’ve followed your tutorials on setting up nginx on a new server running Ubuntu Saucy Salamander (13.10). Unfortunately, the version available from the nginx-stable PPA referenced in your installation tutorial doesn’t include the fastcgi_cache_purge module for Ubuntu 13.10 and the brianmercer PPA doesn’t appear to have been updated to support any version of Ubuntu beyond 12.04 How can I install a version that includes it?

  81. RavanH

    What about excluding caching in case of shopping cart / ecommerce plugins? Would it be OK to add PHPSESSID to the if ($http_cookie ... rule?

    • Rahul Bansal

      Try – https://rtcamp.com/wordpress-nginx/tutorials/plugins/woocommerce/

      • RavanH

        Hi Rahul, thanks I had not seen that post before. Those are very specific rules for Woocommerce but I was thinking about a more general exception that would suit most of the cart plugins out there… Or would adding the PHPSESSID cookie be too much of a ‘shotgun’ approach?

        • Rahul Bansal

          If we skip PHPSESSID cookie then I guess entire site will be skipped unless shopping cart is using session only for sub-section like “/store”.

          In case of woocommerce, it uses session through out sites. Code at other link “clears” cookie headers for non “store” sections. I think similar workarounds may be needed for other cart plugins as well.

          • RavanH

            Ah yes, you’re right… some do indeed start with adding a PHPSESSID cookie right at the first visit while not even having added anything to the shopping cart. I suppose only tailor made solutions like your tutorial for Woocommerce can be applied then. Thanks for the tips :)

  82. JM

    Attempted to follow the instructions to install nginx with fastcgi_cache_purge module, however I was presented with the following after trying to run

    sudo apt-get install nginx-custom

    The following packages have unmet dependencies:
    nginx-custom : Depends: nginx-common (= 1.4.1-0ppa~precise) but 1.4.4-1~precise0 is to be installed
    E: Unable to correct problems, you have held broken packages.

    Nothing urgent, just curious if anyone could help me understand what’s going on.

  83. Paul Lee

    Brian Mercer repository no longer being updated, so instructions above out of date. Think you’d have to build Nginx from source to build fastcgi_cache_purge

  84. Paul Lee

    woops sorry, you’ve already addressed this in the comments! :)

  85. Paul Lee

    Got this working now. Thanks for a great set of tutorials. Learned a lot with regard to LEMP + wordpress networks from your hard work!

  86. David Rahrer

    In reference to building Nginx oneself, I can’t remember but isn’t there a command to reveal the build options so I could duplicate Brian Mercer’s build? (or any build).

  87. Alex

    where i can found for CENTOS 6 nginx with fastcgi_cache purge module support compilied?
    VPS usually uses centos os…

    • Rahul Bansal

      I know http://centminmod.com/ only for CENTOS world. Never used CENTOS since we switched to Nginx.

      About VPS, try DigitalOcean if you like choice of OS, want to spend less for best performance out there! ;-)

      If you can start afresh, DigitalOcean VPS with Ubuntu 12.04 LTS and EasyEngine

      • Jeffrey

        Hi, can I ask why not use nginx with CENTOS, I’m using Amazon Linux AMI, which I understand it’s CENTOS base

        • Rahul Bansal

          You can use any OS on Amazon AWS.

          We prefer Ubuntu. You are free to use Centos. Both works. It’s matter of personal taste. :-)

  88. Alex

    thanx:) will be looking for centos because don’t want change centos….need recompiling i think…hard job for me:)

  89. Alex

    so in config no CSS here:
    ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf

    and if apache stopped this mean site not open correctly because nginx don’t know about css:))

    • Rahul Bansal

      Why you are using Apache? Let Nginx directly talk to PHP-FPM.

      JS & CSS are omitted from above block because we most of the times, use w3-total-cache’s CSS & JS combine/minify feature which needs separate lines for them.

      And when we are not specifying CSS extension like above, nginx will be able to find it correctly via location / { try_files ...} code block.

  90. Michael Smith

    Rahul your tutorials are simply out of this world! Thanks so much for sharing them. I have learned so much from them. With them I have installed nginx, percona mysql, php5-fpm, zend opcache, php-memcache and now fastcgi-cache-with-purging for a wordpress site I am working on. I have a question I have the simplest VPS from Digital Ocean with only 512mb. You mention if you have limited RAM you shouldn’t run from (tmpfs) so in the vhost file fastcgi_pass unix:/var/run/php5-fpm.sock; you can change that to any place in the file system for cached content? So with little RAM you shouldn’t have fastcgi_pass unix:/var/run/php5-fpm.sock; should that be left blank? Or just a path to a different folder on the server?

    Also on a different note what do you use for load testing your site? JMeter, AB Bench.. etc. I am trying to read through documentation online how to use JMeter (it is a bit confusing) but you mention you have 32gb RAM approx how many users can that support on your site? I am trying to figure out and gauge how many users my server can support before upgrading even with the server optimized with all the bells and whistles I have learned from your tuts… Thanks for all your work..

    • Rahul Bansal

      unix:/var/run/php5-fpm.sock is just a socket file.

      I was talking about cache content folder defined by fastcgi_cache_path.

      You can change fastcgi_cache_path /var/run/nginx-cache ... to something like fastcgi_cache_path /var/cache/nginx-cache ...

      • Michael Smith

        Hello Rahul. I apologize it was a typo on my part in regards to fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m inactive=60m; when I referred to just that socket file. I changed it to fastcgi_cache_path /var/cache/nginx-cache .. with my limited ram. Thanks so much. Your tuts are so informative. Keep up the great work.

  91. Nick

    Hi

    In the script above, where is WORDPRESS defined?

    fastcgi_cache WORDPRESS;

    thanks
    Nick

    • Rahul Bansal

      Line: fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m inactive=60m; and

      Line: fastcgi_cache WORDPRESS; are related

      You can use anything instead of WORDPRESS. If you do so, make sure to change it at both places.

  92. DigiMix

    This config works like a charm and helped solve server caching issue on WordPress. Thanks Rahul!

  93. Raymond Ko

    Thank for your great tutorials.

    Yesterday, I started a fresh Digital Ocean VPS, Ubuntu 12.04 LTS, and Easyengine.

    Moved around 10 WP sites using this tutorials, each done by single install.

    ee site create domain.com –wpfc

    Everything works fine, but occasionally I found mysql socket error and it seems either mysql or php5-fpm die periodically. The sites are not public yet and the traffic are pretty low.

    Checked ee info

    PHP ping.path: /ping
    PHP pm.status_path: /status
    PHP pm.max_requests: 500
    PHP pm.max_children: 100
    PHP pm.start_servers: 20
    PHP pm.min_spare_servers: 10
    PHP pm.max_spare_servers: 30
    PHP request_terminate_timeout: 300
    PHP Fastcgi Listen: 127.0.0.1:9000
    ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (111)
    ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (111)
    ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (111)
    ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (111)
    ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (111)
    ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (111)
    ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (111)

    MySQL (5.5.35) Information:

    MySQL User: mysql
    MySQL port:
    MySQL wait_timeout:
    MySQL interactive_timeout:
    MySQL Max_used_connections: /
    MySQL datadir:
    MySQL socket:

  94. Justin

    I’m getting the following error when adding the 3 fastcgi_cache lines to the mysite.com config file:

    root@server:/etc/nginx/sites-available# nginx -t && service nginx reload
    nginx: [emerg] the size 104857600 of shared memory zone “WORDPRESS” conflicts with already declared size 51380224 in /etc/nginx/sites-enabled/mysite.com:4
    nginx: configuration file /etc/nginx/nginx.conf test failed

  95. Configure FastCGI_Cache for WordPress and Nginx | Query Admin

    […] Caching with Nginx on your VPS WordPress deployment: super simple and super fast with nginx caching fastcgi_cache with conditional purging FRiCKLE/ngx_cache_purge Official Debian/Ubuntu […]

  96. Khairul

    Hi Rahul,

    First of all thank you for a great tutorial!

    I’ve been playing with NGINX+FastCGI cache and so far so good, except when I login to wordpress backend, all my links on the website will gave 404 error. However when I logged out from the backend, the error is gone.

    Here is my settings => http://pastebin.com/aDhRcBm5

    Any ideas on what when wrong?

    Thanks in advance.

    • Rahul Bansal

      Try removing:

              error_page 404 /404.html;
              error_page 500 502 503 504 /50x.html;
              location = /50x.html {
                      root /usr/share/nginx/www;
              }
      

      If that doesn’t work, please copy config from this article.

  97. Jeffrey

    Hi, I follow all the steps and get it work now, but when I curl all the pages, i got fast_cgi_cache status BYPASS??
    the page I curl ex: http://i-health.cc/sit-bad-health/

    • Rahul Bansal

      Try adding following line:

      `fastcgi_ignore_headers Cache-Control Expires Set-Cookie`

      After line:

      `fastcgi_cache_use_stale error timeout invalid_header http_500;`

      • Jeffrey

        Tks for the reply

        I get the BYPASS also, does that related to my wc_cookie settings in nginx config?

      • Jeffrey

        Tks for the reply

        I tried adding this line, but get the BYPASS also, does that related to my wc_cookie settings in nginx config?

  98. Micke

    Hi

    Thank you very much for work. You inspired me to try this method of caching. I really like the simplicity of your solution and the Nginx helper plugin. It seems to be the best and most robust solution I have found so far.

    But I have a problem getting wordpress into the cache in the first place. If I place a simple .php or .html file in my wordpress folder it gets cached but none of my dynamic content from wordpress does.

    Do you have any idea what might be the problem?

    Below is my Nginx virtual server config. I have downgraded at the moment, and use the standard Nginx/stable 1.4.5 until I can get the cache working (I did compile from source with cache_purge and it installed fine but it is of no good use if I cannot get wordpress into the cache in the first place). I also have an SSL redirect server and I removed the SSL settings below (they are standard) .

    fastcgi_cache_path /etc/nginx/cache keys_zone=MYAPP:100m inactive=60m;
    fastcgi_cache_key “$request_method$host$request_uri”;
    add_header X-Cache $upstream_cache_status;
    server {

    listen 443 ssl;
    server_name example.com http://www.example.com;
    root /var/www/example.com;
    index index.php index.html index.htm;

    location / {
    rewrite ^/sitemap_index\.xml$ /index.php?sitemap=1 last; ## enables xml-site-maps
    rewrite ^/([^/]+?)-sitemap([0-9]+)?\.xml$ /index.php?sitemap=$1&sitemap_n=$2 last; ## enables xml-site-maps
    try_files $uri $uri/ /index.php?$args; ## enables pretty permalinks
    }

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;

    location = /50x.html {
    root /usr/share/nginx/html;
    }

    location ~ \.php$ {

    fastcgi_split_path_info ^(.+\.php)(/.+)$; #I have “cgi.fix_pathinfo = 0;” in php.ini
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;

    fastcgi_cache MYAPP;
    fastcgi_cache_valid any 1m;
    }

    location ~ /\.ht {
    deny all;
    }

    • Rahul Bansal

      Try adding line: `fastcgi_ignore_headers Cache-Control Expires Set-Cookie;`

      If that doesn’t work, please copy my config as it is.

      • Micke

        Rahul,

        Thank you!

        It works like a charm.

        Micke

  99. Charlie Pryor

    Not sure where to comment this, and I’ve been looking furiously though the web trying to get an answer. Figured I’d go to the source (easy engine).

    When i made my first website on this server with EasyEngine, it was a multisite installation. After I had it up and working, I would see “Welcome to Nginx” when visiting the IP address of the server. – It wasn’t a problem. Didn’t really care all that much. Then it got to where the IP address would visit my website home page… which, again, I didn’t mind. After all, I wanted domain mapping to work anyways.

    I needed to create a few more websites/blogs to go online. So I created a couple more installations of WordPress with your “Create single site” tool with Easy Engine. I imported the databases from the old host, and boom. Works like a charm. – except one problem so far: The IP address now points to the last website I made. This isn’t what I want at all.

    How do I control what people see when they visit my IP address directly? I can I set the primary domain to be the one that is seen (or at least make it the “Welcome to Nginx” screen again)?

    Appreciate your time. Thank you

    – Charlie

  100. ovidiu

    quick question: every few months I compare my setup with this how-to to catch up on new improvements and I just realized my config has a few more * than yours i.e. I use `if ($request_uri ~* (“/wp-admin.*|/cart.*|…` while you use: `if ($request_uri ~* “/wp-admin/|/xmlrpc.php|` – no *

    What exactly is the difference and what is recommend?

    • Rahul Bansal

      That is not a big deal. You can whitelist as many URL as you want. `/wp-admin` is most critical.

      • ovidiu

        Sorry, I should have explained better. What I meant is this:

        Is
        `/wp-admin.*|`
        the same as
        `/wp-admin/|`
        ?

  101. Raspberrypi – wordpress | Nova's RaspberryPi

    […] 아닌 Nginx를 설치해서 사용할 것인데요. Nginx + WordPress + fastcgi_cache with conditional purging 이 페이지에 나오는 형태로 Nginx 자체가 캐시 처리를 하는 fastcgi_cache를 […]

  102. Raspberrypi – wordpress | nova's log

    […] 아닌 Nginx를 설치해서 사용할 것인데요. Nginx + WordPress + fastcgi_cache with conditional purging 이 페이지에 나오는 형태로 Nginx 자체가 캐시 처리를 하는 fastcgi_cache를 […]

  103. Pogoplug – wordpress

    […] 아닌 Nginx를 설치해서 사용할 것인데요. Nginx + WordPress + fastcgi_cache with conditional purging 페이지에 나오는 형태로 Nginx fastcgi_cache 캐시를 워드프레스에서 적절히 […]

  104. Loading… | ThinkThank

    […] Debian, nginx und php-fpm caching plus ein minimalistisches WordPress mit Theme  sorgen für Freude bei der Ladezeit und beim […]

  105. Current server setup for Pers J RP as of July 2014 - Pers J RP

    […] First, Nginx is light on memory. Second, I found it easier to set up. Third, it has built-in, easy-to-use caching features. […]


Comments are closed on this article.
Please use our free support forum for support and discussions.