Last week I noticed that I'd made a rather (un)hilarious security error and exposed my wp-config.php in my WordPress setup to the world. This is bad, as it contains database credentials and some secret keys from the setup (all of which I've had to change since sorting this out). I decided it might be nice to write a small guide on a better setup which while not complete might mean that you're able to avoid the mistakes I've made and possibly to point out a flaw I haven't seen in this new setup. I did look at a couple of other solutions but this one seemed pretty nice to me.

While playing around trying to make this work I did find out about the giant goodie bag of awesome that is the unix find utility. In this case I was using it to change permissions on certain groups of files/directories, and some useful examples are given below. I sense it might come into play a fair bit now and might have some uses I've not thought of.

Before I set off with this one I'm going to issue a few warnings:

  • Your distribution (if you are hosting this on a Linux machine) may have a package for WordPress which makes for a much easier install, and (going with the example of Debian) receives quick, convenient updates through the package manager.
  • You should be familiar with the Linux system including File Permissions, the Apache Web Server, and various other tools.
  • If you get the permissions wrong as I did you can end up letting the world see your config files which include your database credentials and the keys you generate during the setup.

Those issues aside the set up process is relatively simple. As I'm using Debian (stable, which is Lenny at the time of writing) I may make references to Debian specific things such as the package manager apt. Let's get cracking then.

First, you're going to want to install all the relevant modules (run this as root):

apt-get install apache2 php5 mysql-server libapache2-mod-suphp

With those installed you're able to get going with your basic WordPress installation. I'm not going to duplicate WordPress's installation guide, which is available here.

Once you've got WordPress unpacked (I personally chose to set it up in my home directory ~/wordpress/ and add a vhost config in Apache's sites-available with the appropriate directory as the DocumentRoot, there are plenty of guides for this if you do a quick search) you should set about fixing its permissions. For this I chose to use the Linux find program. I don't guarantee that this is the complete set of commands and you should probably check through the installation thoroughly in case I missed one out (I managed to do one of these quite incorrectly initially so I spent a while sorting out the mess I'd caused).

find ~/wordpress/ -type d -exec chmod 755 {} ;
find ~/wordpress/ -type f -exec chmod 644 {} ;
find ~/wordpress/ -type f -name "*.php" -exec chmod 600 {} ;

Having followed the WordPress installation guide you should have a working database (I sort of recommend phpmyadmin for this, especially if you want to do this in a GUI) and configuration. Now for the important part. You need to configure suPHP, and to be honest this is almost completely trivial.  First enable the module:

a2enmod suphp

Then edit the suphp config file at /etc/suphp/suphp.conf so that it contains either the line:

check_vhost_docroot=true

or the line:

docroot=/path/to/your/docroot/

The first will allow suPHP to run anywhere you define a DocumentRoot in your Apache vhost, the latter will allow you to point suPHP to a specified DocumentRoot.

Finally, you need to edit your apache2.conf (found in /etc/apache2/) to turn off the standard apache modphp. I personally use the following config as I have no use for modphp within /home (however if you do you may want to swap phpadminflag for php_flag so that you can enable the module for other php sites you're hosting):

<Directory /home>
  php_admin_flag engine off
</Directory>

<Directory /home>
  AddHandler application/x-httpd-php .php .php3 .php4 .php5 .phtml
  suPHP_AddHandler application/x-httpd-php
  suPHP_Engine on
</Directory>

That should do the job! If I've missed any hilariously crucial stage out then please slap me in a comment so I can add it in.

EDIT (27/05/2009): I probably should have actually explained what suPHP does. All it means is that any PHP files are executed as their owner. In my case the main benefit of this is that the config file doesn't need to be readable to anyone but myself. Possibly a greater advantage, and one which becomes immediately apparent in a shared hosting environment, is that the PHP files are only executed with the permissions of the user. This means that as long as you've got sensible limitations in place on the user anyway, they shouldn't be able to cause any more damage than they could from their shell (and there you can probably see the advantage of the phpadminflag which they cannot override).