“Nobody can hurt me without my permission.” Gandhi**(and anyone who has ever used Linux)
Anyway, even though it’s not directly related to WordPress themes, I’ll be writing a detailed blog post series on my experiences tuning this VPS and WordPress over the next couple of weeks. It might not be directly theme related, but it is definitely indirectly related and we’ll show in future a blog post that your theme choice and theme development practices can have a massive impact on your websites performance. So fuck it I AM on topic.
Anyway one of the final pieces of my VPS config puzzle was figuring out the best way to configure Nginx and PHP-fpm to play nice with multiple websites requiring individual user accounts on the same VPS. On your average shared host, most hosts are running some variant of cPanel/WHM or Plesk. These configs generally have php running under Apache with suEXEC and/or suPHP which allow php to execute under individual user accounts rather than a system user like www-data, php or httpd. This has many benefits from the host’s perspective as it allows for more finely grained control over individual system processes. More importantly, it is a much more secure setup. It’s also one of those rare occasions where security and usability don’t conflict! Why? One of the biggest pain in the asses for people running WordPress under a system account like www-data is that you inevitably end up with one or all of the following predicaments:
- You need to enter ftp account details during the plugin install process which is a pain and may not be an option if your host has disabled ftp in favour of ssh/scp access.
- WordPress automatic updates are a major pain in the ass as it involves setting world writeable permissions to the entire root of your WordPress website – NOT a nice option.
- Image uploads, permalink structure changes and any other WordPress function that requires writing to the disk become a nuisance as it generally means having to go into the shell and setting world writeable permissions on specific files and folders which is not only a pain but is also insecure.
Common but insecure and messy nginx/php-fpm configurations.
While those of your running suPHP don’t have to suffer from these problems, those of us who have moved over to nginx and PHP-FPM don’t have an equivalent to suPHP and so are left searching for an alternative configuration. There are many posts floating around the web suggesting numerous variations on the same theme:
- Chown your webroot to the system user www-data. Add <myuser> to the same group as the user which executes your php scripts e.g. www-data. This setup makes the problems above go away but is inherently insecure. Basically avoid this if you can. Should a hacker be able to upload a php script they will be able to do all sorts of nasty things. Additionally, you will probably have problems transferring files via ftp/scp under the <myuser> account without further messy permissions configuration.
- Chown your webroot to <myuser> and add www-data to the same group as <myuser>. In this scenario <myuser> remains the owner of the files which can solve the ftp/scp permissions issues but basically leave you open to the same security problems highlighted above. Don’t do this either.
A better more secure and usable nginx/php-fpm configuration.
While php-fpm doesn’t have an equivalent to suPHP, the good news is that it doesn’t need one. The process manager configuration options included with php-fpm are immense and very flexible. Is was during my research of these that I stumbled upon a few posts which provided the basis for the following configuration. The good news is that once this is in place you will have all the benefits of suPHP in that you’re scripts will run under a user account of your choice and you won’t need to set permissions on individual files/directories AND you won’t have any ftp/scp transfer issues.
So let’s crack on with the setup:
Step 1: Create user account
Create a new user account. I’m on Ubuntu so I’ll use the following command:
[sourcecode]/usr/sbin/adduser myusernamehere[/sourcecode]
Step 2: Create www directory
As part of the user creation process on Ubuntu a home directory will be created. I suggest you create a “www” directory under that account. You will be configuring your virtual hosts to sit in that location rather than your typical /var/www/ or /srv/www location. This will allow you to setup individual accounts for different users and different websites who will then be only able to access their own accounts. Perfecto.
Step 3: Create website directory structure
Right next step should be to create your virtual host. First, create a few subdirectories under www as follows:
[sourcecode]
mkdir www.mywebsite.com
cd www.mywebsite.com
mkdir logs
mkdir public_html[/sourcecode]
Step 4: Create your nginx vhost
Next, you’ll need to create your nginx conf file for www.mywebsite.com. I’m not going to cover nginx vhost configurations in this post (that will be part of the main post series) but for anyone who knows how nginx/php-fpm works the main difference here is that we are going to pass php requests to a separate process pool than what you might be used to. php-fpm is very flexible in how it handles php process pools. We are going to setup a separate process pool just for www.mywebsite.com in Step 5. For now, amend your vhosts file php block as follows:
[sourcecode]
# Pass PHP scripts on to PHP-FPM
location ~* \.php$ {
try_files $uri /index.php;
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9001;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
[/sourcecode]
Spot the difference? We are now telling nginx to pass php requests to php-fpm on port 9001 instead of 9000.
Step 5: Configure php pool
On Ubuntu 10.10 php5-fpm creates a series of handy configuration files that makes is real simple to create a separate php process pool for individual user accounts. I set one up as follows:
[sourcecode]
cp /etc/php5/fpm/pool.d/www.conf mywebsite.conf
[/sourcecode]
Crack open mywebsite.conf and edit some key variables as follows:
[sourcecode]
; Start a new pool named ‘myuser’.
[myuser]
listen = 127.0.0.1:9001
user = myuser
group = myusergroup
[/sourcecode]
You should also configure your child processes accordingly. I keep mine dynamic and keep a small number of children for each pool rather than having a large number of children in a main default process pool. I generally work off a base of 5 children per website but you will need to setup your config based on your specific environment.
Restart nginx and php-fpm and you should be up and running!
[sourcecode]
/etc/init.d/nginx restart
/etc/init.d/php5-fpm restart
[/sourcecode]
That’s it!
I’ve been testing this config for a few days and everything is working swimmingly well.
I’d love to hear anybody’s feedback and comments with regard to their experiences with this config.
Stay tuned for more VPS tutorials in the near future.
Leave a Reply