Are you using Varnish on your WordPress blog? Possibly the Varnish script by Unixy? Great! Get rid off it. Here’s why you should drop Varnish immediately and configure Nginx and W3 Total Cache properly.

I started with an open mind, but quickly discovered that Nginx (frontend) + Apache (backend) is a far superior combination than Varnish (cache) + Apache (backend). I also discovered that Varnish is basically useless in many scenarios and more of a burden and that Nginx is far superior (not necessarily because its faster, see below).

Nginx Cache Config WordPress.png

Varnish: Inferior Cache With Bugs And Configuration Hell

First let me point out that Varnish is a great script and it definitely has a few use-cases, but for smaller and medium sized WordPress sites with up to 50,000 hits per day it is the worst thing you can possibly install. Varnish is not easy to maintain and it has to be updated frequently. It is also consuming a lot more resources than Nginx.

Last, and most importantly, Nginx already includes everything that Varnish provides. A built-in cache and support for 3,000+ simultaneous connections. It is rare that you hit more than 3,000 connections. If you know how to properly configure Nginx as a front-end proxy and enable the built-in caching system, nginx can handle even more than that.

Varnish Does Not Work Well With WordPress

You see, WordPress sessions require all sorts of cookies. Unfortunately, Varnish is an inferior cache when it comes to configuration. Varnish out of the box will stuff everything into a single config file, whereas Nginx scripts such as Nginx admin neatly put vhosts, proxy and server settings into different files. As a programmer or server administrator, you will learn to appreciate a tidy environment and Varnish is a complete mess (out of the box).

Nginx, WordPress and W3 Total Cache: How To Make Them Work Nicely Together

WordPress and Nginx are an excellent combination. After benchmarking various configurations for a few days, here are my findings:

1 CRITICAL: Turn Of W3 Total Cache Browser Cache GZIP Compression

It is critical that you turn off GZIP compression within W3 Total Cache and turn on GZIP compression via Nginx. By default W3 Total Cache and Nginx may both have GZIP turned on and it’s never a good thing to compress already compressed files. This should be #1 on your to-do list. If you do not turn off the compression you will run into all sorts of issues and Nginx may serve no html files at all and instead will bypass W3TC completely, serving WordPress PHP files. There are obviously compatibility issues. You could write some Nginx location rules, which I tried, but gave up on after realizing how superior Nginx’s compression algorithm is. Let Nginx handle the compression and W3 Total Cache the minification, CDN, database, enhanced page and object caches.

2 Adding Expires Headers To HTML FIles

It is recommend that you set an expires header EVEN to your HTML files if you do not deploy frequently.

If you post once or twice per day, there should absolutely be an expires header on all your HTML files. 1 hour caching will deliver outstanding results and will not greatly affect user experience.

If you are serious about performance, there is only one way to go. And you can always create cronjobs to delete critical files like your frontpage. I learnt not to rely on W3 Total Cache due to its many bugs and flaws (not so rare for a complex plugin such as this one).

3 Turn On Nginx Caching (MUST DO For 0.00 CPU LOAD!)

If you use Nginx admin open up /nginx/ and change proxy_buffering off to ON to enable the built-in cache. This cache will GREATLY increase your Nginx performance and GREATLY decrease CPU load. During my tests I went from 0.6 CPU load to 0.3 avg CPU load and eventually even 0.00 despite numerous Apache processes running. Enabling this cache is a must. Set the cache size to 1500 and your site will fly and your resource usage will go down by half or more!

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=microcache:150m inactive=24h max_size=1500m;

4 Avoid File Cookies

Cookies are bad. Period. Always avoid all cookies except session cookies. Don’t set cookies for static files.

5 Turn On W3TC Cache Compatibility

Enable W3 Total Cache Compatibility (General Settings Page) – the 20% decrease is incorrect, it’s barely noticeable and will prevent all sorts of issues that I encountered. I tested for quite a while. In fact, I was about to drop W3 Total Cache for one of the alternatives until I found this setting.

6 Disable UTF8 File Encoding (W3TC)

Check the option “Disable UTF8” – this will prevent improper character encoding by W3 Total Cache. During my test I discovered that W3 Total Cache will add incorrectly encoded code to the first line of all html files. This will cause major issues from time to time and even cause rendering issues. Please note that this will only effect file encoding and will not affect your site negatively.

7 Debugging WordPress

Make sure to debug everything you find. W3 Total Cache, Nginx and WordPress will only play well together if they don’t encounter any fatal PHP crashes. PHP crashes may not be apparent when you load your site yourself, but turn on your debug log and use tail -f debug.log within your WordPress content dir (wp-content) to monitor the debug file for a while. You will see how well your site works and if there is anything to debug.

8 Nginx High Keep-Alive Values: 40 To 100

Nginx much like Apache requires a high keep-alive value. Test values from 40 to 100. Yes, I am serious 100. Apache may only be able to handle 5 to 15, but Nginx can handle much higher keep-alive times while keeping CPU load at 0.00 – quite incredible. (Please note my setup: 16GB RAM, SSD – you may have to experiment a little on a VPS or shared hosting!)

9 Nginx Timeouts

A lot of idle connections will kill your resources. Although Nginx is kind of a wunderkind, you should set some timeouts that are more reasonable than the default 3m (minutes!) that Nginx uses by default.

client_header_timeout 1m;
client_body_timeout 1m;
send_timeout 1m;

You should experiment a little, try this too:

client_header_timeout 30s;
client_body_timeout 30s;
send_timeout 30s;

10 Up Your Worker Connections

Finally, make sure to have enough worker connections.

In your nginx.conf change it to:

worker_connections: 7200

On a server with 16GB RAM and Quad-Core or better:

worker_connections: 19000

Eventually try:

worker_connections: 30480

The more workers the better Nginx will handle incoming connections. Far superior to anything Apache and Varnish could do.