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

261 responses to “fastcgi_cache with conditional purging”

  1. 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. 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?

    • @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.

        • 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)

          • 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!

          • @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.

  3. Excellent article, thank you.

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

    Thank you.

      • 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.

  4. 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

  5. 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

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

  6. 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.

    • @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.

  7. 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

    • 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.

  8. 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 ?

  9. 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

    • @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?

      • 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.

  10. @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!

    • @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.

  11. Oh, I missed this earlier.

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

      • 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.

    • 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)

  12. 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.

    • 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!

      • 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.

        • 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)?

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

            }

  13. 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";
    	}	
    
    • 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.

      • 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.

        • 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.

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

          any ideas?

  14. 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.

    • 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. 🙂

      • 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.

        • 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.

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

  16. 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

    • 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/

      • 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.

  17. 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.

  18. 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

  19. 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

  20. 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

    • @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
      
  21. 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

  22. 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.

  23. 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;
    	}
    
    • 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.

  24. 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.

  25. 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.

    • 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?

        • 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?

        • 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!

          • 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.

          • 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 😉

    • 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?

      • 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! 😉

  26. 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.

    • 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?

    • 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.

  27. 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.

  28. 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.

  29. 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?

    • @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

  30. 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

  31. @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.

  32. @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.

  33. 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”;`

  34. 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).

  35. 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?

    • 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.

  36. 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,

    • 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.

  37. 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?

  38. 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

  39. 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

    • 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.

        • 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?

  40. 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?

    • 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!

      • 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?

  41. 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?

    • 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.

  42. 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.

    • 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).

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

      • 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?

        • 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.

  44. 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?

    • 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.

  45. 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?

    • 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.

      • 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?

  46. 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
  47. Another question: is it totally redundant to use fastcgi_cache and a wordpress plugin such as WP-SuperCache?

  48. 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

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

  50. 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.

    • 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.

      • 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.

      • 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.”

        • 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!

          • 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….

          • 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. 🙂

  51. 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

  52. 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!

    • 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.

      • 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.

  53. 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?

    • 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.

  54. 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

  55. @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,

        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.

        • 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!

  56. 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.

    • 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.

  57. 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)?

  58. 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.

    • 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.

      • 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…

        • 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.

  59. 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!

    • 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.

  60. @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!

    • 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.

  61. 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?

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

      • 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?

        • 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.

          • 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 🙂

  63. 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.

  64. 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

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

  66. 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).

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

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

  69. 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:))

    • 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.

  70. 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..

    • 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 ...

      • 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.

  71. Hi

    In the script above, where is WORDPRESS defined?

    fastcgi_cache WORDPRESS;

    thanks
    Nick

    • 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.

  72. 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:

  73. 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

  74. 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.

    • 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.

    • Try adding following line:

      `fastcgi_ignore_headers Cache-Control Expires Set-Cookie`

      After line:

      `fastcgi_cache_use_stale error timeout invalid_header http_500;`

      • Tks for the reply

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

      • 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?

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

  76. 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

  77. 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?

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

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

  78. Question… I get Cache Hit on the home page but not subpages … this seems to be cause by:

    if ($query_string != “”) {
    set $skip_cache 1;
    }

    Wouldn’t it make sense to cache other pages? (except when a real query string is sent = ?arg)

    From the docs:

    $query_string
    same as $args

  79. Hi, I have a hard time finding info how to setup nginx cache behind traefik proxy. It would be great if someone would share such info.