In this mini-tutorial, upon bluesdog's request (original thread here), I'm going to present suPHP - an Apache module allowing one to run the PHP process on a per-user basis, not worrying about safe_mode and leaving the matter of setting file permissions to the users' discretion.
Note: suPHP is probably a lot slower than the normal Apache module as it has to fork a PHP process and set the proper UID/GID when processing a HTTP request for PHP. Therefore, use whenever needed, but not in case of single-user, trusted sites (in such case I recommend Lighttpd + FastCGI).
Who this is for
This howto is aimed at virtual hosting providers - be it a home server with just a few accounts, or promising enterprise-grade installations willing to take on thousands of users.
Goals
Following this howto should lead to a setup in which every PHP script on the web server is executed with UID and GIDD of its respective owner - that is, as if called by that user and with the exact same privileges as the owner. The setup will be based on UNIX user account separation - users may not interfere with each other. Security shall be attained by means of traditional UNIX access rights, and file management shall be left to users themselves via means of FTP or any other filesystem access methods capable of assigning access rights (chmod).
Motivation
While other different means of attaining the goals exist, this one seems to be the most current and the most broadly used within Apache2+PHP servers. The solution, on the other hand, changes UID/GID only for PHP scripts, so it is not as versatile as using apache2-mpm-itk (allows to configure per-vhost uid/gid, but you have to use config files for vhosts - mass vhosting not possible, bad for large deployments), or apache2-mpm-peruser (which is almost unknown, difficult to get and compile, and considered generally unused). If no other scripting languages besides PHP are going to be used on your web server, this is the right solution.
My recipe
First, of course, you need Apache version 2. I recommend getting apache2-mpm-worker:
Code: Select all
apt-get install apache2-mpm-worker
Code: Select all
a2enmod userdir
Then, install the appropriate PHP, along with all modules you might need, and suphp:
Code: Select all
apt-get install php5-cgi libapache2-mod-suphp
Now, edit /etc/suphp/suphp.conf:
Set docroot appropriately - if all your files are under /srv/www, for example, then set it to /srv/www. If using mod_userdir, just set it to /home (if that's where all your home directories are) or /
It is also necessary to set check_vhost_docroot to false when using suPHP in conjunction with mod_userdir.
Then, set min_uid and min_gid to some reasonable values. Assuming that your users will be in group www-data (33) and that you want to run some PHP scripts as the first vhosting user with a UID of 1000 (ie your users' uids start at 1000), you can set min_uid=1000 and min_gid=33
Save the file and leave the editor.
Enable suPHP and restart apache2:
Code: Select all
a2enmod suphp && /etc/init.d/apache2 restart
Code: Select all
adduser --ingroup www-data joe
# fill in the user's data
su - joe
mkdir public_html
cd public_html
echo -e "<?php\nphpinfo();\n?>" >phpinfo.php
chmod 0700 phpinfo.php
If it works, you probably see a security concern arising - virtual users are able to read any file on the system, unless you use open_basedir or other limitations. However, the problem of users spying on one another has been silently handled in the previous code snippet - that is: the users have to set their PHP files to be 0700. What is more, any files that are not meant to be accessed by the web server should be set to 0700, too (database configs etc.). So say we have an example web application consisting of:
Code: Select all
index.php
style.css
db_config.ini
product_image.jpg
uploaded_files/
Then we set the access modes as follows:
index.php, db_config.ini, uploaded_files: 0700 - they do not need to be read by anyone besides PHP itself at any moment. PHP will be executed with the owner user's UID and GID, so the process is capable of writing to uploaded_files and reading its config from db_config.ini. The latter should never be accessible to strangers - you don't want your database passwords to leak.
style.css, product_image.jpg: 0755 - may be read by anyone - the webserver will not setuid() to the target user because suPHP faciliates this only for PHP scripts, so we need to make sure that the user Apache is running as (www-data) can read the files. The file mode could as well be 0750, provided that the file group is set to www-data.
If everything goes well, you should have setup a functional vhosting site by now.
EDIT: Just followed this tutorial on a development machine and it works. Happy hosting!