Nginx + APC + fastcgi_cache all working on one site but on another

Hi,

I recently decided to switch to nginx for some of my blogs as an exercise to learn more about nginx before putting it into use for my eCommerce startup. Great help with the tutorials, thanks!

Currently, I am using DigitalOcean VPS, the starter plan ($5 a month) with 512MB RAM and 20GB SSD. It's pretty decent and I figure for 3 or 4 Wordpress blogs, it will be enough given that the configuration for nginx + APC + fastcgi_cache is going to take out a lot of work from the PHP + MySQL.

The setup is not multisite setup. It is single Wordpress installations for each domain. So far, I have only setup two sites. One is a fresh install, and another one I moved from MediaTemple Grid.

I followed the tutorials pretty much and read more on each too. The setup went rather well and my first site is working fine with fastcgi_cache. I did use $upstream_cache_status in order to test if fastcgi_cache is working. For my first domain, it's working. The result for rt-Fastcgi-Cache in HTTP response is usually a HIT. If there is a MISS, I run again and it will be a HIT.

However, for second site, it is not working for some reason. Everytime I check HTTP response, it is always a MISS.

Here is HTTP response for first domain:

HTTP/1.1 200 OK  
Server: nginx/1.4.1  
Date: Thu, 19 Sep 2013 08:44:13 GMT  
Content-Type: text/html; charset=UTF-8  
Connection: keep-alive  
X-Powered-By: PHP/5.5.3-1+debphp.org~precise+2  
X-Pingback: http://www.domain1.com/xmlrpc.php  
rt-Fastcgi-Cache: HIT  

Here is HTTP response for second domain:

HTTP/1.1 200 OK  
Server: nginx/1.4.1  
Date: Thu, 19 Sep 2013 08:45:15 GMT  
Content-Type: text/html; charset=UTF-8  
Connection: keep-alive  
X-Powered-By: PHP/5.5.3-1+debphp.org~precise+2  
Set-Cookie: _icl_current_language=en; expires=Fri, 20-Sep-2013 08:45:15 GMT; Max-Age=86400; path=/  
X-Pingback: http://seconddomain.com/xmlrpc.php  
rt-Fastcgi-Cache: MISS  

(For some reason, non-www of domain1 would be having 301 redirect to www, while www version of seconddomain will be rediredicting to non-www. I'll look into it later but shouldn't be a problem. And result of rt-Fastcgi-Cache is still the same for both with and without www)

Here is my nginx.conf

user www-data;  
worker_processes 4;  
pid /var/run/nginx.pid;  

events {  
    worker_connections 768;  
    # multi_accept on;  
}  

http {  

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

## For Cache Testing Without Shutting Down PHP  

add_header rt-Fastcgi-Cache $upstream_cache_status;  

    ##  
    # Basic Settings  
    ##  

    sendfile on;  
    tcp_nopush on;  
    tcp_nodelay on;  
    keepalive_timeout 65;  
    types_hash_max_size 2048;  
    # server_tokens off;  

    server_names_hash_bucket_size 64;  
    # server_name_in_redirect off;  

    include /etc/nginx/mime.types;  
    default_type application/octet-stream;  

    ##  
    # Logging Settings  
    ##  

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

    ##  
    # Gzip Settings  
    ##  

    gzip on;  
    gzip_disable "msie6";  

    # gzip_vary on;  
    # gzip_proxied any;  
    # gzip_comp_level 6;  
    # gzip_buffers 16 8k;  
    # gzip_http_version 1.1;  
    # gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;  

    ##  
    # nginx-naxsi config  
    ##  
    # Uncomment it if you installed nginx-naxsi  
    ##  

    #include /etc/nginx/naxsi_core.rules;  

    ##  
    # nginx-passenger config  
    ##  
    # Uncomment it if you installed nginx-passenger  
    ##  

    #passenger_root /usr;  
    #passenger_ruby /usr/bin/ruby;  

    ##  
    # Virtual Host Configs  
    ##  

    include /etc/nginx/conf.d/*.conf;  
    include /etc/nginx/sites-enabled/*;  
}  


#mail {  
#   # See sample authentication script at:  
#   # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript  
#   
#   # auth_http localhost/auth.php;  
#   # pop3_capabilities "TOP" "USER";  
#   # imap_capabilities "IMAP4rev1" "UIDPLUS";  
#   
#   server {  
#       listen     localhost:110;  
#       protocol   pop3;  
#       proxy      on;  
#   }  
#   
#   server {  
#       listen     localhost:143;  
#       protocol   imap;  
#       proxy      on;  
#   }  
#}  

Here is domain1's config:

server {  
        server_name domain1.com www.domain1.com;  

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

        root /var/www/domain1.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-(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 $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 /index.php;   
        include fastcgi_params;  
        fastcgi_pass unix:/var/run/php5-fpm.sock;  

        fastcgi_cache_bypass $skip_cache;  
            fastcgi_no_cache $skip_cache;  

        fastcgi_cache NGINXCACHE;  
        fastcgi_cache_valid  60m;  
    }  

    location ~ /purge(/.*) {  
        fastcgi_cache_purge NGINXCACHE "$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; }  
}  

And here is config file for seconddomain:

server {  
    server_name seconddomain.com www.seconddomain.com;  

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

    root /var/www/seconddomain.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-(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 $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 /index.php;   
        include fastcgi_params;  
        fastcgi_pass unix:/var/run/php5-fpm.sock;  

        fastcgi_cache_bypass $skip_cache;  
            fastcgi_no_cache $skip_cache;  

        fastcgi_cache NGINXCACHE;  
        fastcgi_cache_valid  60m;  
    }  

    location ~ /purge(/.*) {  
        fastcgi_cache_purge NGINXCACHE "$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; }  
}  

I will try to install third website and see if fastcgi_cache has any effect on it. And yes, I've installed Nginx Helper plugin for second domain as well and turned it on.

Thanks for your tutorials! Hope you can shed some light on this :D

Okay, I installed another WordPress installation on a new domain and tested. Fastcgi_cache is working. Then I thought it might be the theme so I installed the same theme from seconddomain, and the cache is still working. So I started working through the plugins and it turns out WPML Multilingual CMS plugin is the one causing all the issues.

With just the plugin itself, it doesn't cause any problem. What happens is when you enable "Browser Language Redirect", which enables WPML to detect the browser language and show the pages in that language. In my "seconddomain" website, it was enabled before and the setting got carried over when I moved it to my new VPS with nginx.

So in the test domain, I checked HTTP response after I installed WPML Multilingual CMS plugin. Fastcgi_Cache is working. Then when I enabled Browser Language Redirect from the plugin, Fastcgi_Cache only shows MISS instead of HIT on pages. So I disabled Browser Language Redirect. Guess what? Fastcgi_Cache is still not working.

Turns out, it's an issue causing by a cookie. Here is the line from HTTP response

Set-Cookie: _icl_current_language=en; expires=Fri, 20-Sep-2013 08:45:15 GMT; Max-Age=86400; path=/  

I cannot turn that off, as there is no settings on it. I could edit the WPML plugin files and comment out the cookie usage but it could potentially disrupt the functionality of WPML.

So I am wondering if you guys have any solutions on it.

Thanks in advanced, guys!

I added the following to nginx.conf and now it's working!

fastcgi_ignore_headers Cache-Control Expires Set-Cookie  

What I want to know is if this is the correct approach. Oh and whenever I access /purge, it always give me 404 error. Not sure why.

Okay, scrap what I said. /purge/ is now working fully well too :D

@samuel.faith

Looks like you manage to solve your issue by yourself.

Regarding line:

Set-Cookie: _icl_current_language=en; expires=Fri, 20-Sep-2013 08:45:15 GMT; Max-Age=86400; path=/

Looks like you are using WPML plugin. If you are serving a page on same URL in multiple language, where language selection depends on cookie-value, you might run into issues here.

In that case, workaround would be to modify:

fastcgi_cache_key "$scheme$request_method$host$request_uri";  

To include $cookie_icl_current_language

fastcgi_cache_key "$scheme$request_method$host$request_uri$cookie_icl_current_language";  

Please note that you will also need to modify location /purge accordingly.