Nginx Rewrite Rules for W3 Total Cache Plugin

This article contains Nginx rewrite rules for w3 Total Cache plugin, converted from apache's (.htaccess) rewrite rules. Nginx configuration given in this post is tested and found to be working.

We have been using nginx from long time to run our WPMU + domain mapping configuration for rtBlogs network.

Recently when we decided to switch from Wp Super Cache to W3 Total Cache plugin, we were stuck while translating apache’s (.htaccess) rewrite rules to nginx configuration.

Now, after some efforts we managed to get nginx working with W3 Total Cache plugin with following rewrite rules.

# if the requested file exists, return it immediately
if (-f $request_filename) {
    break;
}

## W3 Total CACHE BEGIN
set $totalcache_file '';
set $totalcache_uri $request_uri;

if ($request_method = POST) {
  set $totalcache_uri '';
}

# Using pretty permalinks, so bypass the cache for any query string
if ($query_string) {
  set $totalcache_uri '';
}

if ($http_cookie ~* "comment_author_|wordpress|wp-postpass_" ) {
  set $totalcache_uri '';
}

# if we haven't bypassed the cache, specify our totalcache file
if ($totalcache_uri ~ ^(.+)$) {
  set $totalcache_file /wp-content/w3tc-$http_host/pgcache/$1/_default_.html;
}

# only rewrite to the totalcache file if it actually exists
if (-f $document_root$totalcache_file) {
  rewrite ^(.*)$ $totalcache_file break;
}                 

##W3 Total CACHE END

# all other requests go to WordPress
if (!-e $request_filename) {
    rewrite . /index.php last;
}

Above codes will sit inside server{ location{ } } block.

Our original configuration file is too big and contains many unwanted things so I am not publishing it here.

Anyway, if you stuck somewhere, feel free to use comment form below. 😉

Update: For those who are faceing issues with gzip (compression)…

I have a code block at the beginning of  location /{} block in our nginx configuration file as below:

          location / {
               gzip  on;
               gzip_http_version 1.0;
               gzip_vary on;
               gzip_comp_level 3;
               gzip_proxied any;
               gzip_types text/plain text/html text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
               gzip_buffers 16 8k;
               .....
        }

Above code-block basically “asks” nginx to turn on compression when files with listed mime types (see line gzip_types) being served

When above lines are present in your configuration, you can altogether disable compression settings from w3 Total Cache as nginx webserver will automatically handle compression for those requests. Not tested though.

29 Comments

Steve June 22, 2010

Awesome thank you for sharing – does it matter if we’re using disk/apc/xcache or whatever for caching?

Rahul Bansal June 27, 2010

@Steve
Rewrite rules are needed for disk-based caching only.
In other modes like APC/xcache/memcache/etc you do not need any kind of rewrite rules at all.

Michael June 24, 2010

A few issues with this setup – it will only actually rewrite to the cached disk files, so this setup isn’t actually any better than using supercache. It won’t work with minified files, and the CDN integration probably won’t work either.

Rahul Bansal June 27, 2010

@Michael

Regarding…

A few issues with this setup – it will only actually rewrite to the cached disk files, so this setup isn’t actually any better than using supercache

There cannot be comparison in this context as the whole point of adding these code was to remove wp-super-cache and use only one plugin for CDN, page-caching & to minify js/css.

For…

It won’t work with minified files, and the CDN integration probably won’t work either.

I will check minified files regarding issue as on the setup on which this is tested, minification is not turned on yet.
But CDN, in origin-pull (mirror) mode is configured and working fine.

Thanks for your inputs though. 🙂

Scott June 26, 2010

All seems to be working with the exception of minify. As soon as I try to minify a css file it fails to find it. It seems the url is getting written wrong.

http://www.domain.com/wp-content/w3tc/min/tomorrow/tomorrow/default.include.483068540.css

That just doesn’t look right to me. searching the file system it seems the file doesn’t even exist either. I also found out that if I uncheck “Rewrite URL Structure” it works but much much slower than it should be.

Any idea’s?

Rahul Bansal June 27, 2010

@Scott
As noted by Michael in above comment, rewrite rules given by me wont work with minifiy settings.
I will find a work-around soon.
Thanks for your feedback. 🙂

Marco Romeny June 26, 2010

Oh wow! Can’t wait to try it out! Been looking for a solution for some time!

Marco Romeny June 26, 2010

I had to remove -$http_host and append .gzip from my rule, so it now looks like:
set $totalcache_file /wordpress/wp-content/w3tc/pgcache/$1/_default_.html.gzip;
Are you guys using the dev version of w3tc? I am using the stable released..
It seems to work though so far! Haven’t tested heavily yet..

Rahul Bansal June 27, 2010

@marco
I am using stable release of w3 total cache.

I am not using compression option in w3 total cache.
In my case, I am using nginx gzip settings which I added in above post just now.

If you still want to use gzip from w3 total cache I guess you can use try_files block.
I will do my bit of research and will soon update nginx conf that will work with gzip as well as minify options given in w3 total cache.

Joost Schuur August 1, 2010

@Rahul: Since W3 Total Cache can already create static gzipped files for you, why would you have nginx do compression on the fly every time?

At least nginx won’t attempt to recompress a .gzip file because it doesn’t match it’s mime types of what to serve compressed.

I also noticed no HTTP host reference in my pgcache directory path (currently testing 0.9.1.1) and the cache file base name was _index.html and not _default_.html.

Rahul Bansal August 2, 2010

@Joost
I faced some issues in getting .gzip files to work from disk storage.
So I opted-in for APC cache. Also Doncha used nginx on-the-fly compression in his guide here.
In my case, I have 2GB RAM on my VPS. APC eats up less than 60MB for storing cached pages in RAM so I went for APC.
You can also check my discussion with Fredrick (w3 total cache developer) and others on APC v/s disk-storage here.

I was really expecting better support for nginx in recent w3 total cache release but nginx support is moved to future release (1.0 version).
For my clients, I still want to figure out pure nginx configuration which should work with disk-based gzip compression, js/css minification with rewrites.
As playing with nginx consumes a lot of time, I am not sure if I will be able to figure out nginx rules myself in this month 😐

Max August 4, 2010

Thanks for your rewrite rule.

I am testing the W3 total cache as well. But I found that there is no page generated under pgcache directory. I already enable page cache and I think it will generate some files under that directory, am I correct?

I am running nginx + wordpress 3.01 + multisite(subdirectory) + domain mapping. Thanks.

Gravity August 27, 2010

I came across this whilst looking for answers to a similar problem. I have Apache, W3TC, WordPress and phpBB and wanted to install eaccelerator. I then had all kinds of strange rewrite failures on the phpBB rewrite rules, haven’t solved them yet, but will leave a trail of my investigations over here in case it helps others.

Todd September 13, 2010

When using minify settings, are you able to bypass nginx to get php to generate the combined css or js files? For me I’m noticing it hit’s the missing file on request and php never get’s the request…

Krish November 20, 2010

Thanks for the gzip config 🙂

Winter December 4, 2010

Ok I’m pretty sure everything is working with my install of nginx, wordpress and w3 total cache.. this is without playing with any re-writes except the permalinks in the wordpress.conf file. However, after doing speed page testing at webpagespeedtest.org I keep getting a grade of “F” on browser caching. Can anyone help?

By the way I am using the development version of w3 total cache which is stated to have nginx support.

If anyone has any answers it would be greatly appreciated. Thank you

Marc January 24, 2011

When is the cache deleted/updated? f.e. if a new comment was added.

Winter February 10, 2011

I give up on private server till SOMEBODY ON THE INTERNET can figure out how to make this whole process of having a speedy wordpress site simpler on a nginx server. I’ve seen about 10,000 solutions to rewrites and no one agrees on it. It’s all incredibly confusing for newcomers.

Marco February 11, 2011

Totally untested, but the first block could be written something like this:

location / {
if( $request_method = POST ) { set $w3tc_pass = 1;}
if( $query_string) { set $w3tc_pass = 1;}
if ($http_cookie ~* “comment_author_|wordpress|wp-postpass_” ){ set $w3tc_pass = 1;}
try_files $uri $uri/ /wp-content/w3tc-$http_host/pgcache/$request_uri/_default_.html /index.php?$args;
}

try_files is recommended over rewrites and testing for existance of files (it does’s it internally..)
Will try this somewhere and see if it works…

Marco February 11, 2011

Um.. forgot the conditional on $w3c_pass — not good to be on the phone while writing..

Marco February 11, 2011

Here we go – still untested, still four if’s (would be great to reduce that):

location / {
if( $request_method = POST ) { set $w3tc_pass = 1;}
if( $query_string) { set $w3tc_pass = 1;}
if ($http_cookie ~* “comment_author_|wordpress|wp-postpass_” ){ set $w3tc_pass = 1;}
if($w3c_pass){
try_files $uri $uri/ /index.php?$args;
}
try_files $uri $uri/ /wp-content/w3tc-$http_host/pgcache/$request_uri/_default_.html /index.php?$args;
}

Marco February 11, 2011

Don’t try the above – can’t have try_files inside if’s…

Sunil Sheoran March 10, 2011

W3TC is a good plugin .I have tested it and have been using it for a while. I find it realy useful.