This WordPress Setup Lets You Sleep Well With 10.000.000 Page Impressions

When running a website with a lot of page impressions you need two things: a headache-free infrastructure able to scale with increasing traffic, and, a fine-tuned software setup in order to get the most performance out of your hosting. After seeing an ever increasing traffic hitting our project LigaLIVE this is what we learned.

Varnish + Apache Load

Bingo! This is how it should look like: a high cache hit rate (0.98), low load (0.03) while only a few requests hit your backend.

Headache-Free Infrastructure Is Key

Infrastructure-setupA future-proof infrastructure doesn’t have to be expensive, nor does it need to be extremely complicated. We have had good experience using the following base setup:

  • Cloudflare as DNS and layer for improving website security while reducing bandwidth hitting your infrastructure. In our setup Cloudflare delivers all of our static assets including images, stylesheets and javascript. For running automated tasks like cronjobs we have defined a couple of custom page rules for excluding those from cache. Already the free version of Cloudflare immediately improves performance and security but there is also a paid version giving you more control of the setup.
  • Amazon Web Services as hosting infrastructure that is very easy to adapt according to your current needs. AWS provides us with Multi A-Z RDS with automatic failover for MySQL, EC2 Instances for Varnish and Apache and ElastiCache as memcache, and, other great tools to keep our systems running and backed up (Snapshots anyone?).
  • Varnish Cache as reverse proxy is caching about 90% of our anonymous traffic and delivering all our pages, generated as static file by W3 Total Cache. The remaining 10% are POST requests or logged in traffic for administering WordPress.
  • Apache as web server serving dynamic pages with PHP using APCu. You can use Apache 2.4 in conjunction with php-fpm or swap it with nginx to your liking.

The Setup For High Performance

Next to a Multisite WordPress Setup with a couple of general plugins for building out website features the most important piece of the puzzle is W3 Total Cache in combination with Varnish.

W3 Total Cache Configuration

  • aggregation and minification of stylesheet and javascript files: while this mostly works for self-written code some plugins stop working due to a dirty way of writing code. If you don’t want to run into problems I suggesst using manual minification and add specific files to the minification process. Apart from a couple of useful WordPress plugins we are using W3 Total Cache in order to speed up the site.
  • HTML minification: this only works then you have the php5-tidy extension installed
  • object cache and database cache using APCu / OpCode Cache. Have a look at your PHP error log in order to find possible problems when reading / storing data in APC.
  • Page caching in Disk Enhanced mode in order to deliver those static pages to Varnish and caching it until eternity purging.
  • Varnish Purging of the front- and overview pages when a new post is published

Varnish 3 VCL Configuration for WordPress With Cloudflare + W3 Total Cache

Don’t mix: Varnish and Vary: User-Agent

W3 Total Cache sends “Vary: User-Agent” when using Browser Cache. This effectively renders Varnish useless, i.e. brings cache hit rate extremly down because a copy is saved for every User-Agent out there (Ex.: Mozilla, Webkit, etc.). You can come by that issue by either removing the according lines in your .htaccess file, tuning Apache to not send the User-Agent, or, by ignoring the User-Agent in your varnish configuration. We went with the method of adding configuration to our Varnish.

Keep NextGen Gallery from locking your database rows

The combination of W3 Total Cache and NextGen Gallery seems to create problems at our RDS with writing and deleting one row at the same time. In order to circumvent this problem we hacked the NGG plugin and removed this function:

register_shutdown_function(array(&$this, '_update_tracker'));

Get rid of Simple Ads Manager Maintenance Calls

If you are using SAM for simply inserting ads in your posts that are actually delivered by DoubleClick For Publishers and you don’t need tracking you should remove the call to sam-ajax.php that gets fired on every page load.

samAjax.mailer &&, {action: "sam_maintenance"});

Traffic Analysis Opens The Blackbox

In order to configure the optimal setup for the traffic you have at hand it is of outmost importance to analyze it thoroughly. Below is a collection of useful tools and shell snippets we are using on a daily basis.



apachetop -d 1 -f PATH_TO_YOUR_ACCESS_LOGS

The command apachetop shows you all traffic hitting apache. A successful varnish configuration would show that most requests are only done one time, the next request would be served directly from Varnish. Except for AJAX POST requests of course.




varnishstat shows you the most important metrics at a glance: amount of cache hits and misses i.e. requests hitting your backend, client connections, objects that need to be purged, etc.

varnishlog -m "VCL_call:miss" | grep "RxURL"

Realtime view of URLs missing the cache, i.e. going through to your backend.

varnishlog -c -m RxRequest:PURGE

Helping you to debug Cache Purging via your CMS, for example using WordPress and W3 Total Cache

WordPress P3 Plugin


P3 Plugin Performance Profiler

Analyze which plugins bring down your performance by measuring their impact on your site’s load time.

WordPress Query Monitor Plugin


Query Monitor

Analyze what database queries are fired during a page load, how long they take and by what plugin / function they are caused. Essential when finding poorly written plugins or code that might bring your site down in high traffic situations.

Let us know in the comments should you have any feedback, questions or comments about this setup.

The following two tabs change content below.
Born in Vienna, living in Berlin. Founder/CEO of appstretto. Over 15 years of experience in the digital world. Adventurous, bold & passionate.

Latest posts by Nader Cserny (see all)