High Performance WordPress – Part 2

So it’s taken much longer to push out Part 2 of the High Performance WordPress post series but it’s back and hopefully won’t have as big a gap for Part 3! Last time in Part 1 we got you as far as selecting a VPS host (still loving Linode!) and your OS selection (Ubuntu 10.10).
Today, we’re going to dive into getting your shiny new VPS machine up and running on the most kickass, hottest web server stack making big big waves in the WordPress community and further afield. First, let’s take a look at what we hope to achieve:

  • OS setup – Optimizing Ubuntu as a web server.
  • Web Server Setup – nginx setup and configuration – whoa – no Apache? Yup that’s right folks we’re hooking you up with the fastest web server on the planet!
  • DB Server Setup – Good ‘ol mysql will still be our data layer.

OS Setup

I’m a great believer in not reinventing the wheel. In addition to being a brilliant host, Linode also offer a fantastic Library which provides documentation for setting up just about every kind of hosted platform you could think of in their data centres. It should be safe to assume at this point that you’ve setup a Linode running Ubuntu 10.10 and you’ve been able to login to that server as root via the shell. Too much already? This tutorial is probably not for you. Maybe go play with your new Linode and go through the Linode Library to figure out basic shell commands before continuing with this guide.

For those still paying attention now would be a good time to configure your basic Ubuntu instance with some sensible defaults. This is where the Linode Library and the Linode Getting Started guide comes in dead handy – this System Admin basics guide is great for sorting things like your timezone and installing htop. Go do that first. DON’T install any web servers just yet. We’ll get to that shortly.

All done? A quick checklist of the most important things should have just done:

If you do have any problems be sure to hop on over to the Linode forums. There are some super smart really helpful people over there.
Let’s move on.

Web Server Setup

Why nginx?

Simply put – nginx rocks! Don’t get me wrong – I still love Apache. It’s been around forever and is still by far the most popular web server run WordPress. But Apache is a victim of it’s own success. Most common Apache deployments come with a LOT of baggage. Baggage that tends to not really matter for low traffic websites, but once you start to build your traffic levels it quickly becomes a bit of a dog unless you really understand how to tune it properly. It doesn’t help that the default Apache configuration is entirely inappropriate for modern VPS environments. nginx is a lightweight traffic handling powerhouse that is blisteringly fast with minimal configuration. The real beauty of nginx is just how much traffic you can throw at it on very modest low powered VPS machines. If you still don’t believe nginx is a viable alternative to Apache or Lightspeed or other new kids on the block like Cherokee, just take a look under the hood of WordPress.com (currently the 18th busiest website in the whole fricking world!) – which web server powers it? nginx. ‘Nuff said.

Install nginx

You’ll find a ton of tutorials online about how to install nginx. Personally, I’ve found this process as outlined on the nginx wiki is the most straightforward one. You’ll find lots of other tutorials suggesting installing it from source but to be honest with you if you’re not 100% comfortable with install packages from source already – now is not the time to start. The process I’ve described below will take you 5 minutes to complete and it won’t install a version of nginx that is horribly outdated (which the default ubuntu 10.10 packages are). We’ll also add a little twist to the install process which will become critical in a later part of the guide.

NOTE: If you attempt the nginx Ubuntu install commands, you’ll probably find that Ubuntu tells you that add-apt-repository is not installed. Go ahead and install that first by running:

[sourcecode]
apt-get install python-software-properties
[/sourcecode]

After you have the python properties installed, go ahead and run the following:

[sourcecode]
sudo -s
nginx=stable
add-apt-repository ppa:nginx/$nginx
apt-get update
[/sourcecode]

Now normally, you would then simply run apt-get install nginx to complete the process. Well here is the little twist. We’re going to install a little gem which will make your life a little bit easier later on when we get to configuring caching servers. We’re going to install the nginx-extras PPA which contains the latest and greatest stable full version of the nginx web server and a whole load of other nginx extras and modules – (the full list of nginx extras contained in this package are here) meaning we won’t need to compile nginx from source later to add in common extras like HTTPRealIPModule (which will be very useful later when we configure our caching server Varnish). Hat tip to melon in the Linode forums.

So go ahead and install nginx with the extra goodies as follows:

[sourcecode]
apt-get install nginx-extras
service nginx restart
[/sourcecode]

Assuming you’ve a nice clean install process you should now be able to fire up your browser and enter your machine IP/hostname and see a nice big “Welcome to nginx!” welcome message. Congrats you’re now up and running with the world’s fastest web server!

On Ubuntu, the following a basic nginx commands that you’ll get to know pretty quickly:

service nginx stop – Stop web server
service nginx start – Start web server
service nginx restart – well I think you’re getting the idea by now!
service nginx status

Install PHP

Next up is PHP. Again this is pretty simple. We’re going to install PHP-FPM (FastCGI Process Manager) instead of your vanilla PHP version. PHP-FPM is an alternative FastCGI implementation designed specifically to cater for websites with high volumes of traffic where granular control over process management becomes essential.

First off, we’re going to install a nice of valuable PHP modules during the main install process – PHP-FPM throws a tantrum on Maverick about a missing web root folder. It looks for a web root folder in /var/www/ (which Apache would normally create). To avoid seeing the error during the php install process, go ahead and create this directory:

[sourcecode]
mkdir /var/www
chown www-data:www-data /var/www
[/sourcecode]

Now go ahead with the PHP install process:

[sourcecode]
apt-get install php5-fpm php5-cgi php5-common php5-suhosin php-apc php5-mysql php5-dev php5-curl php5-gd php5-imagick php5-mcrypt php5-snmp
[/sourcecode]

This will take a few minutes to run given the number of packages we’re installing in one go. Go read twitter for a few minutes.

Once the install is done, give everything a quick recycle to make sure all new settings kick in:

[sourcecode]
service php5-fpm restart
service nginx restart
[/sourcecode]

You may get this error during the PHP restart:

[WARNING] [pool www] pm.start_servers is not set. It’s been set to 20.

To supress this warning, we’ll go ahead and set a number of processes for php to start with in  /etc/php5/fpm/pool.d/www.conf

[sourcecode]
pm = static
pm.max_children = 5
[/sourcecode]

Don’t worry too much right now about what is going here. In a nutshell we’re setting a sensible default for how many php processes will be created on your small VPS. In the future as you become more familiar with how PHP-FPM processes are managed you can tweak this a lot more to tune it for your specific environment.

Go ahead and restart PHP-FPM (no need to restart nginx).

PHP5-FPM Hello World Test

Then to make sure everything is working as expected, we’ll create a simple “Hello World” php page to ensure nginx is communicating properly with your PHP Backend. The default nginx web root is in /usr/share/nginx/www

[sourcecode]
cd /usr/share/nginx/www
touch hello.php
nano hello.php
<!–?php phpinfo(); ?–>
[/sourcecode]

Save the file (CTRL-X) and Y.

Before we load the page, there’s one more config change we need to make. We need to tell nginx to pass off any requests for files ending with *.php to be passed to the PHP-FPM backend. Thankfully nginx comes with some simple config rules which can just be uncommented to activate this immediately on the default web root.

[sourcecode]
cd /etc/nginx/sites-available/
nano default[/sourcecode]

Scroll down and uncomment the following lines:

[sourcecode]
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
}

[/sourcecode]

Save the file and restart nginx.

Go to your browser and load http://myip/hello.php

You should see something like this:

Congratulations – you’ve just finished your basic nginx/php configuration!

We’ll be coming back to this in Part 3 when we start to setup new web roots for your main WordPress website and add in WordPress specific nginx config rules. For now though we’ll go ahead and get MySQL up and running.

Install MySQL

MySQL is very easy to get up and running on ubuntu. For this part of the guide, we’re essentially following this Linode guide.

[sourcecode]

apt-get install mysql-server mysql-client

[/sourcecode]

Follow the on screen instructions (I think it’s just setting the root password from memory!)

Once the installer is done, run the MySQL hardening process to secure your installation:

[sourcecode]
mysql_secure_installation

[/sourcecode]

It’s safe to assume you should follow the default prompts suggested on screen.

The Linode guide suggests further tweaks to the MySQL configuration file (my.cnf) to further tune MySQL for optimal performance in a low memory environment. These are definitely worth implementing.

Setup test database and user

Ok so now we’ve got MySQL up and running, let’s go ahead and test everything to ensure it all works as expected.

[sourcecode]
mysql -u root -p
[/sourcecode]

Enter your MySQL root password (not your shell root password) when prompted:
then,

[sourcecode]
create database testdb;
grant all on testdb.* to ‘testusr’ identified by ‘strongpassword’;
[/sourcecode]

(NOTE: don’t forget the dot after your database name – that’s not a typo.)

Assuming all goes well that pretty much confirms MySQL is installed and running correctly. Let’s setup phpMyAdmin to make db management a little easier!

Install phpMyAdmin

This one is pretty straightforward too.

[sourcecode]
apt-get install phpmyadmin
[/sourcecode]

You will be prompted to select a web server. Straight away you’ll notice there’s no nginx option! Never fear it’s safe to select Apache 🙂

Again follow the on screen instructions to complete the install.
Once the install is done we need to tell nginx about it. If you wished you could setup a dedicated virtual host like dbmgmt.mydomain.com but I prefer to run phpMyAdmin off my IP on a separate port which is a bit more secure and can be locked down at the firewall.

Let’s go ahead and do that now.
This is our first foray into nginx vhost setup aswell!
cd /etc/nginx/sites-available
touch phpmyadmin
nano phpmyadmin

Enter the following nginx config:

NOTE: Make sure you set correct values for:

listen: This should be the port you want to run the virtual host off – I’ve chosen 8084
server_name: This should be your public IP address. Everything else in the file should be fine as is.

[sourcecode]
server {

listen   8084;
server_name XX.XX.XX.XX;

access_log /var/log/nginx/localhost.access.log;

root   /usr/share/phpmyadmin;
index  index.php;

location / {
try_files $uri $uri/ @phpmyadmin;
}

location @phpmyadmin {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME /usr/share/phpmyadmin/index.php;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_NAME /index.php;
}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
fastcgi_pass   127.0.0.1:9000;
fastcgi_index  index.php;
fastcgi_param  SCRIPT_FILENAME  /usr/share/phpmyadmin$fastcgi_script_name;
include        fastcgi_params;
}
}[/sourcecode]

UPDATE: Once you save this file, you’ll also need to enable this new site. Thanks to Alex for spotting this omission!

[sourcecode]ln -s /etc/nginx/sites-available/phpmyadmin /etc/nginx/sites-enabled/phpmyadmin[/sourcecode]

Save the file and restart nginx.

Go to http://myip:8084/

You should see the phpMyAdmin login screen. Go ahead and login with the root details creating during the install. And that’s phpMyAdmin installed!

Ok that’s it for Part 2 folks. We’ve covered a lot of ground today but we’re still only scratching the surface of our WordPress High Performance Guide. Part 3 will take us the full WordPress installation and configuration process for the nginx environment we have setup. Until next time!


Comments

13 responses to “High Performance WordPress – Part 2”

  1. Great guide!
    When is the Part 3 coming?

    1. Thanks Alex! – it’s 50% complete so hopefully a little bit later this week – is there anything I can help you with in the meantime?

      Ed

      1. Yeah Ed,
        I’m trying to get more than one domains on nginx (editing the config file like in this guide: http://is.gd/exLbTj ) but it doesn’t work! I managed to do it (display html – other than “Welcome to nginx”) by editing the “default” file in sites-available and sites-enabled.

        But I’m confused on how to do it for multiple sites! I’m getting an unable to connect or redirection error for all the sites!

        Also, your code for installing the PHP isn’t working (with Linode). I managed to install PHP using wget and installing the tar file.

        Let me know if you can help me,
        Alex

        1. Hey Alex,

          What error did you get with the PHP install? It’s a pretty standard install process – did you set the directory permissions prior to the install as I outlined?

          The Linode tutorial you linked to is pretty much the process I follow for creating all my sites. Do you get an error with your nginx restart after saving the config? nginx is normally good at spotting any config problems before they become an issue.

          Ed

          1. Nevermind Ed,
            I worked all day today and managed to install and run WordPress perfectly! After countless hours of frustration and 6 rebuilds :p

            Also, switched to CentOS 6!

            1. Great to hear you got it working in the end Alex! CentOS is a great platform too.

              Ed

              p.s.
              Just published Part 3 🙂
              http://themesforge.com/performance/high-performance-wordpress-part-3/

  2. Also, you need to add to your code after you’re done with mysql exit
    And after you’ve created the phpmyadmin file in sites-available you have to link it in sites-enabled or else it won’t work:

    ln -s /etc/nginx/sites-available/phpmyadmin /etc/nginx/sites-enabled/phpmyadmin

    1. yes, well spotted – I’ll update this shortly. Thanks for the good catch!

      Ed

  3. I think a variable was updated since the writing of this article.

    If you are getting this error:

    Restarting nginx: nginx: [emerg] unknown “https” variable

    You can comment out # fastcgi_param HTTPS $server_https;
    in /etc/nginx/fastcgi_params

    1. Hi Danny,

      Yes you are right – this mainly impacts newer nginx versions. Thanks for sharing.

      We’re in the middle of collating our high performance series into a little ebook and hope to update it to reflect some of these little changes.

      Ed

  4. Hi Ed,

    I’m using this tutorial for making my first nginx server for WordPress and I faced an issue (probably because it’s a new version but I need to say it here). In your /etc/nginx/sites-available/default config you put:

    fastcgi_pass 127.0.0.1:9000;

    but if we are using php5-fpm for cgi, we need to change this line for this one:

    fastcgi_pass unix:/var/run/php5-fpm.sock;

    as we are using php-fpm for CGI in this tutorial. Otherwise, we will have errors like these:

    2012/09/24 11:30:51 [error] 20343#0: *197 FastCGI sent in stderr: “Primary script unknown” while reading response header from upstream, client: xx.xx.xx.xx, server: localhost, request: “GET /sqlweb/scripts/setup.php HTTP/1.1”, upstream: “fastcgi://unix:/var/run/php5-fpm.sock:”, host: “xx.xx.xx.xx”

    2012/09/24 13:13:42 [error] 25198#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: xx.xx.xx.xx, server: xx.xx.xx.xx, request: “GET / HTTP/1.1”, upstream: “fastcgi://127.0.0.1:9000”, host: “xx.xx.xx.xx:8084”

    In fact, in the default file it says it and you have to uncomment the right line:

    # With php5-cgi alone
    # fastcgi_pass 127.0.0.1:9000;
    # With php5-fpm:
    # fastcgi_pass unix:/var/run/php5-fpm.sock;

    Hope it can helps anyone.

    Cheers.

Leave a Reply

Your email address will not be published. Required fields are marked *