Super power WordPress using Nginx

Nginx is a powerful tool when used properly. WordPress.com is powered completely by Nginx and I am sure they are handling much more traffic than our sites combined – so you can safely assume it can scale extremely well. So let’s jump right into the deep end here, starting the requirements for this post:

  • An Ubuntu VPS running 12.04 LTS (I suggest Rackspace or Linode)
  • Basic understanding of SSH

Disclaimer

I am going to assume you know for the most part what you are doing and I am not responsible if you take down your live website while trying to convert Apache to Nginx or any other non-sense.

Updates & Upgrades

Besides changing your root password, the very first thing you should always do with a new VPS is update and upgrade your software using apt-get.

apt-get update apt-get upgrade  

You will see a bunch of text go flying by and for right now that means you are on the right track. This may take a while so if you need to use the bathroom the next rest stop is not for another 192 miles.

Installing Nginx & Friends

Now that the VPS is all nice and updated you need to start installing software.

apt-get install nginx php5-fpm php5-mysql php5-apc php5-curl php5-cli php5-mcrypt php5-gd mysql-server unzip zip  

You will again see a bunch of text flying by but will also be prompted a few times by the MySQL installation at the end. Be sure to set the MySQL root password and remember it.

Start your engines

Now that everything has been installed, go ahead and start up the services! If you browse to the servers public IP in your browser of choice you should see a nice white page with black text that says “welcome to nginx!”

service nginx start service php5-fpm start  

Don’t use root

After today you are banned from logging into your server using ROOT. Actually lets make sure you cannot do that, this is very good for security. The command below will open the nano editor.

nano /etc/ssh/sshd_config  

Use the down arrow key to scroll down until you find PermitRootLogin and then change yes to no. After you’ve made that change just press Control+X on your keyboard, hit the Y key saying “Yes I want to overwrite this file,” and then press enter confirming the file name. This change will not go into affect until you have restarted SSH.

service ssh restart  

Since you just locked out root from logging in directly via SSH (do not worry you can still access root using the su or sudo commands) you will need to start logging in with a new user. So think long and hard about what username you want to use for the rest of this VPS’ life – for the purposes of this demo I’m going to use pmgarman as my username. You can add a user using the useradd command, including the username and then I also always include the -m argument so the home directory is created automatically. By default the users home directory is going to be located in the /home/{username} directory.

useradd -m pmgarman  

Websites do not belong in /var/www

I am not a fan of websites being stored in the /var/www directory of a server. I cannot explain any real reason behind it, the location of a site is pretty much open to wherever you want it but it bothers me. I want a bit more structure in my web servers so all sites are organized in a /home/{username}/{domainname} format. This just simplifies so many things in the setup of a web server and allows for an infinite number of users and sites (assuming your server can handle it) and at any given time you can fairly easily figure out where the site is.

Install and Configure WordPress

There are a couple different steps and this is possibly one of the most important parts of this demo – so pay attention. Go get a cup of coffee if you have to but just be careful because one typo could easily cause errors and then the sky will fall, but not until you’ve already moved on and then do not know where you made a mistake.

To start off with we will download WordPress and put it in it’s proper location. This is very simply done with wget, unzip, and mv. Before you download anything you will want to change the directory you are in to the users home directory. Keep in mind you are doing all this as root so you also need to change the ownership of the site files to your user.

cd /home/pmgarman  
wget http://wordpress.org/latest.zip  
unzip latest.zip  
mv wordpress pmgarman.me  
chown pmgarman:pmgarman pmgarman.me -R  

Now you have WordPress sitting and ready to go in your home directory and your user even owns them! Because the files are in the users home directory you do not have to mess with funky permissions or changing groups, forget all the confusing stuff you have been trying to do. That user. Has permission. To modify it’s own files.

Oops, you thought you were done.

Now that you have your site files, you need to configure Nginx and PHP to start working for you. Again as with the users and sites, some planning and organization can go a long way here. The way your server will work is each user will have their own PHP “pool” – which is just that users dedicated PHP processes. With each user having their own PHP processes you can easily manage the resources a single user has access to, and that pool will also run as the user so permissions are taken care of once again. PHP looks for its pool configurations in /etc/php5/fpm/pool.d so change to that directory. Then rename the default pool to anything that does not end in .conf (since PHP) will only load files ending in .conf), and create your own pool. I typically use 2 processes and force PHP to use a static number instead of dynamically spawning processes as it feels like it. This all goes back to planning ahead, if I know I can run about 10 PHP processes on a certain VPS then hard coding the number that are running makes for easy math.

Note: I prefer UNIX sockets over TCP/IP, it may only be a small performance improvement but it makes me feel good inside. The one caveat is you need to create the directory the socket files will live in – that is what line 3 below does for you.

cd /etc/php5/fpm/pool.d  
mv www.conf default  
mkdir -p /var/run/php5-fpm  
nano pmgarman.conf  

Since you are now staring at a blank text editor you may need a configuration to model after 🙂 Just replace all pmgarman references with your own username.

[pmgarman] listen = /var/run/php5-fpm/pmgarman.socket listen.backlog = -1 ; Unix user/group of processes user = pmgarman group = pmgarman pm = static pm.max_children = 2 pm.max_requests = 500 ; Pass environment variables env[HOSTNAME] = $HOSTNAME env[PATH] = /usr/local/bin:/usr/bin:/bin env[TMP] = /tmp env[TMPDIR] = /tmp env[TEMP] = /tmp

Nginx is going to by default look in /etc/nginx/sites-enabled for any configuration file. Typical practice is to place your configurations into /etc/nginx/sites-available and then symlink them to the sites-enabled directory. That way if you want to disable a site but keep its configuration you just delete the symlink. What I have found is if I have one Nginx configuration per user, and then all that users sites within that file I’ve been able to manage things fairly easily.

cd /etc/nginx/sites-available nano pmgarman ln -s /etc/nginx/sites-available/pmgarman /etc/nginx/sites-enabled/pmgarman

Here is another configuration for you to model your own after, just be sure you replace all username and domain name references with your own (hint: don’t forget the last username reference at the bottom). This configuration is modeled after the one provided on the WordPress Codex > Nginx page. I’ve added a phpMyAdmin location block since that is used by most

upstream pmgarman {  
    server unix:/var/run/php5-fpm/pmgarman.socket;
}

server {  
    server_name pmgarman.me www.pmgarman.me;
    root /home/pmgarman/pmgarman.me/;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    rewrite /wp-admin$ $scheme://$host$uri/ permanent;

    location /phpmyadmin {
        root /usr/share/;
        index index.php index.html index.htm;
        location ~ ^/phpmyadmin/(.+.php)$ {
            try_files $uri =404;
            root /usr/share/;
            include fastcgi_params;
            fastcgi_intercept_errors on;
            fastcgi_pass pmgarman;
        }

        location ~* ^/phpmyadmin/(.+.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt))$ {
            root /usr/share/;
        }
    }

    location ~ .php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on;
        fastcgi_pass pmgarman;
    }
}

phpMyAdmin, if you’re into that kind of thing…

I am not a fan of phpMyAdmin myself but in a pinch it gets the job done. You can install phpMyAdmin by running the following commands. You do not want to reconfigure the web server for phpMyAdmin, but you do want to install dbconfig-common when prompted, and you can leave the phpMyAdmin password blank so one can be randomly generated (you will not need to know that one, ever).

apt-get install python-software-properties software-properties-common add-apt-repository ppa:nijel/phpmyadmin  

Restart your services and install WordPress!

Now that Nginx is configured for your site, PHP is setup to run a pool just for you (you always wanted your own pool right??), phpMyAdmin is installed (yuck).. it is time to finally install WordPress. Before you can do that you need to restart Nginx and PHP and just hope you did everything right 🙂

service nginx restart service php5-fpm restart  

If all went well you should see no errors! If you did see any I am sorry I failed you 🙁 but just go back through your configurations and see if maybe you missed a step. Nginx is good about pointing out where the error occurred but for PHP you will want to check the /var/log/php5-fpm.log file for some insight.

From this point on you are on your own, you will need to get to phpMyAdmin (if I had installed phpMyAdmin then it would be at https://pmgarman.me/phpmyadmin – but I didn’t so do not try going there) and setup a user and database for your site. Then browser to your domain and install WordPress.

Happy pressing of words!