Hey folks I’m back with Part Three of the High Performance WordPress guide. If you’ve not done so already, be sure to check out Parts One and Part Two which will take you from a position of having no server to a fully configured VPS machine running the kickass nginx web server and mysql – or a LEMP environment as those in the know like to call it.
Today, we’ll proceed with setting up WordPress on our shiny new VPS server.
Create an nginx Virtual Host
First things first, let’s smarten up our nginx configuration to make things play nice with WordPress. I’ve learned to love nginx conf files. In the beginning it was a bit different from configuring Apache but once you get beyond this initial learning curve you realise nginx really is a very very clever little fellow that’s been really well designed.
nginx’s nerve centre can be found in /etc/nginx/
We’ll be spending most of our time in 3 place within this directory:
- nginx.conf – the master nginx config file which contains global host configuration information
- sites-available and sites-enabled – these 2 apache’esque directories control your virtual host website specific configuration files. Host config files are created in sites-available and symlinked back to sites-enabled – very similar to how Apache works. We’ll show you this in more detail very shortly.
Editing nginx.conf
I’m not going to go into massive detail on editing your overall nginx.conf in this tutorial. You’ll find tons of stuff in Google on this if you’re that way inclined. The default config works pretty well out of the box. The most important thing to ensure is that you have these 2 lines in your nginx.conf:
[sourcecode]
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
[/sourcecode]
These 2 lines simply tell nginx to also load any conf files found in these 2 locations when it is being started/reloaded. These is critical for the rest of this tutorial.
Create a home directory for your websites
For simplicity, I like to store my websites in /srv/www but this is pure personal preference. You choose a different location like /var/www or /home/site/www/ if you wish. For now let’s assume you’ll follow along with me.
[sourcecode]
mkdir -p /srv/www/engin.ex/public_html
mkdir -p /srv/www/engin.ex/logs
[/sourcecode]
One directory will serve your content while the other is for your log files. Pretty simple eh?
Now let’s tell nginx about our new site location.
Creating an nginx virtual host for WordPress
Ok so let’s make an assumption that you wish to run WordPress on a domain of some sort (pretty safe assumption I would think!). Let’s go with engin.ex (see what I did there) as our dummy domain example. First we create a file called engin.ex in /etc/nginx/sites-available/
[sourcecode]
cd /etc/nginx/sites-available/
touch engin.ex
[/sourcecode]
Now you’ll probably want to crack open your favourite text editor and copy/paste the following nginx config and tweak it for your domain name.
[sourcecode]
# W3TC config rules based on http://elivz.com/blog/single/wordpress_with_w3tc_on_nginx/
server {
listen 80; ## listen for ipv4; this line is default and implied
#listen [::]:80 default ipv6only=on; ## listen for ipv6
# Tell nginx to handle requests for the www.engin.ex domain
server_name www.engin.ex engin.ex;
if ($host != ‘engin.ex’) {
rewrite ^/(.*) http://engin.ex/$1 permanent;
}
index index.php index.html index.htm;
root /srv/www/engin.ex/public_html;
access_log /srv/www/engin.ex/logs/access.log;
error_log /srv/www/engin.ex/logs/error.log;
# Use gzip compression
# gzip_static on; # Uncomment if you compiled Nginx using –with-http_gzip_static_module
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_buffers 16 8k;
gzip_http_version 1.0;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript image/png image/gif image/jpeg;
# Rewrite minified CSS and JS files
rewrite ^/wp-content/w3tc/min/([a-f0-9]+)\/(.+)\.(include(\-(footer|body))?(-nb)?)\.[0-9]+\.(css|js)$ /wp-content/w3tc/min/index.php?tt=$1&gg=$2&g=$3&t=$7 last;
# Set a variable to work around the lack of nested conditionals
set $cache_uri $request_uri;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $cache_uri ‘no cache’;
}
if ($query_string != "") {
set $cache_uri ‘no cache’;
}
# Don’t cache uris containing the following segments
if ($request_uri ~* "(\/wp-admin\/|\/xmlrpc.php|\/wp-(app|cron|login|register|mail)\.php|wp-.*\.php|index\.php|wp\-comments\-popup\.php|wp\-links\-opml\.php|wp\-locations\.php)") {
set $cache_uri "no cache";
}
# 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") {
set $cache_uri ‘no cache’;
}
# similar to Apache Status – handy for quickly checking the health of nginx
location /nginx_status {
stub_status on;
access_log off;
allow all;
}
# Use cached or actual file if they exists, otherwise pass request to WordPress
location / {
try_files /wp-content/w3tc/pgcache/$cache_uri/_index.html $uri $uri/ /index.php;
}
# Cache static files for as long as possible – removed xml as an extension to avoid problems with Yoast WordPress SEO plugin which uses WP rewrite API.
location ~* \.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
try_files $uri =404;
expires max;
access_log off;
}
# Deny access to hidden files
location ~* /\.ht {
deny all;
access_log off;
log_not_found off;
}
# Pass PHP scripts on to PHP-FPM
location ~* \.php$ {
try_files $uri /index.php;
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
}
[/sourcecode]
Whoa that’s a lot of code! We’ll go into what this does in another post some time. For now, you can trust me that these config rules work pretty darn well on some high traffic WordPress websites. For now, the final step is your symlink back to sites-enabled:
[sourcecode]
ln -s /etc/nginx/sites-available/engin.ex /etc/nginx/sites-enabled/engin.ex
service nginx restart
[/sourcecode]
In the config file above I would obviously substitute enign.ex for whatever your domain is of course! Don’t forget that step for your config. I’ve used this config example on a good few WordPress powered websites for the past year with no real issues. It’s pretty stable. Those of you paying attention will also have spotted that this config is also optimised for use with W3 Total Cache. More on that aswell a little bit later. For now, let’s get WordPress installed and up and running.
Install WordPress
Nothing majorly complicated here.
[sourcecode]
cd /srv/www/engin.ex/public_html
wget http://wordpress.org/latest.tar.gz
tar -zxvf latest.tar.gz
cp -rvf wordpress/* .
rm -R wordpress
rm latest.tar.gz
[/sourcecode]
These few commands above will get you your WordPress source ready for a clean install. Just before we do that, let’s hop back across to phpMyAdmin and create a new DB for our WordPress install. I won’t go into details about how to do that here – tons of stuff online to help you with that. Also, now would be a good time to head back over to Part 2 if you’ve skipped the phpMyAdmin install earlier.
Oh I almost forgot, one more thing you should do is set permissions on your public_html to be writable by the www-data user. There’s definitely one or two more secure ways of setting permissions on your web root but they always tend to have a trade off of making plugin and image uploads a little bit tricky. For now, we’ll set this and we’ll come back to a little bit more secure setup a bit later.
[sourcecode]
chown -R www-data:www-data /srv/www/engin.ex/public_html
[/sourcecode]
Right out of the gates this basically gives nginx permission to write files to your web root (nginx.conf sets the main system user account to use to be www-data, the same account Apache uses on Ubuntu). We’ll benefit from this straight away as the WordPress installer will be able to write your wp-config.php to the filesystem.
Whip up your browser and hit http://engin.ex/ – you should see the first screen of the WordPress install process. Complete the famous 5 minute install.
Tuning WordPress for nginx
Assuming you’ve made it this far you could stop right now and you’d have a pretty kickass nginx powered WordPress setup. But where would the fun be in that? Let’s crack on and soup up this server to be even more badass!
nginx and Permalinks
If you’re used to running WordPress on Apache, you’ll be definitely aware of what a .htaccess file is. Well, nginx doesn’t use .htaccess files. Everything is configured in your config file over in /etc/nginx/sites-available. But don’t fret – we included some nice WordPress rewrite rules earlier so go ahead and setup and switch on your favourite permalink config.
nginx Plugins for WordPress
Given nginx’s recent popularity a few plugins have started popping up in the community which help optimize WordPress for nginx environments which deserve a mention. One in particular is nginx Compatibility – This is a great little plugin and one I recommend as a must have. WordPress has some builtin functions to check for the presence of mod_rewrite which is an apache module used for url rewriting. Obviously nginx doesn’t have this module and when WordPress doesn’t detect it, there can be problems with your permalink structure. When this plugin is used it tricks WordPress into thinking mod_rewrite is present and any potential rewrite problems melt away.
Install W3 Total Cache
It would be a real shame to get this far in the guide and to not really turn your server into a traffic serving beast! W3 Total Cache (W3TC for short) will do just that. There are a handful of really really good caching plugins for WordPress. Other than W3TC, the other few I’ve used a lot are:
- Super Cache – The grand daddy of WordPress caching plugins. It’s pretty damn good too. There’s not much to choose between Super Cache and W3 Total Cache. In fact many people prefer it to W3TC and have less trouble configuring it from scratch. It’s code is top notch which is to be expected given it’s written by top WordPress developer, Automattic employee and all round good guy Donncha O’Caoimh. It also plays nice with nginx once you’ve tweaked for your config accordingly. (Sidenote: we’re not covering an nginx Super Cache config today but if you’re interested Donncha himself provided one some time ago and a more recent one from Tim Purewhite which actually looks great – thanks for sharing Tim!.)
- Quick Cache – This is new kid on the block and I’ve used it on a few WordPress powered websites running on Apache. I’ve not used it in anger on an nginx server yet. I do recall playing around with it and I don’t recall everything running smoothly but I didn’t delve further. But it works great on Apache and it’s gathering a lot of momentum recently.
Why I prefer W3 Total Cache
I’m not here to debate which caching plugin is better than the other. Tons of people quite frequently put together comparisons between this feature and that and spend more time than I ever could analysing the finer points of how many requests per second one plugin can serve over another. In reality there’s not much between all of the plugins mentioned here. I prefer W3TC simply because in my view pound for pound it gives provides the best all around feature set and performance of all these plugins in a VPS environment and it’s pretty simple to get working well with nginx. It also has support for Varnish cache purging and Opcode caching which we’ll be coming back to in Parts 4 and 5. That’s before we even mention the brain power behind this plugin. The frickin CTO of one of the busiest blogs on the planet Frederick Townes built W3TC from scratch so this plugin has had some serious road testing!
If you’re looking for a really detailed guide to W3 Total Cache do not look beyond Tentblogger’s incredibly detailed and totally awesome W3TC setup and configuration guide – thanks John!. You can safely ignore John’s permission and .htaccess settings as we’ve taken care of both earlier in this guide. But everything is pretty much bang on for a pretty well optimised W3TC setup. Go ahead and install W3TC and follow the Tentblogger setup guide.
If you’ve followed that tutorial carefully you shouldn’t have any issues. How can you check if it’s working? I would recommend starting with Disk enhanced caching for your page caching. In later tutorials we’ll get into Opcode caching. For now once you select enhanced Disk page caching and you browse to your website frontend (and you’re not logged into WordPress!) you should see some files getting written to /wp-content/w3tc/pgcache/ – make sure you click around a few pages and see that additional files and folders are being written to the disk. All good! Great – your initial W3TC config is complete. But what about our .htaccess rules I hear? Well the nginx config we setup earlier already has them built in! Your frontend should now be serving cached content and if you enable the W3TC page caching debug output you should see something like this in your websites source:
[sourcecode]
<!– Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/
Served from: www.engin.ex @ 2011-11-02 22:53:52 –>
<!– W3 Total Cache: Page cache debug info:
Engine: disk: enhanced
Cache key: sample-page/_index.html_gzip
Caching: enabled
Status: cached
Creation Time: 0.044s
Header info:
Set-Cookie: w3tc_referrer=http%3A%2F%2Fengin.ex%2F; path=/
X-Pingback: http://engin.ex/xmlrpc.php
Content-Type: text/html; charset=UTF-8
Last-Modified: Wed, 02 Nov 2011 22:53:52 GMT
Vary: Accept-Encoding, Cookie
X-Powered-By: W3 Total Cache/0.9.2.4
Content-Encoding: gzip
–>
[/sourcecode]
I’d recommend switching off the debug once you’re happy everything is working correctly.
Take a deep breath and path yourself on the back.
That pretty much wraps up Part 3 – well done on making it this far! By now your new WordPress website is a finely tuned traffic munching animal. You’ll be ready to handle thousands more requests than a normal WordPress install running on Apache with no caching. In part 4 we’re going to venture further down the rabbit hole of High Performance WordPress tuning when we take a look at Opcode caching and how to stress test your new server. Feel free to raise any questions you have in the comments below and we’ll factor to them into future posts in the series!
Leave a Reply