Scheduled Maintenance: We are aware of an issue with Google, AOL, and Yahoo services as email providers which are blocking new registrations. We are trying to fix the issue and we have several internal and external support tickets in process to resolve the issue. Please see: viewtopic.php?t=158230

 

 

 

suPHP for Apache - multi-user PHP web hosting made easy

Share your HowTo, Documentation, Tips and Tricks. Not for support questions!.
Post Reply
Message
Author
thewanderer
Posts: 416
Joined: 2007-03-19 18:11
Location: my desk, Warsaw, Poland

suPHP for Apache - multi-user PHP web hosting made easy

#1 Post by thewanderer »

Hello,
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
If you want to do vhosting for virtual users, you might want to use mod_userdir. If so, enable it:

Code: Select all

a2enmod userdir
Now, every user can have their website under ~/public_html/.

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
The configuration of PHP itself is skipped as it is not the topic. Just a quick reminder: you probably want to use the recommended php.ini settings available at /usr/share/doc/php* - or at least turn off magic_quotes_gpc.

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
Now, you should be ready to try the setup out. Let's create an example user, an example directory for him and put an example file there. In case you are not using mod_userdir but for instance mod_vhost_alias, adapt the below instructions accordingly - the important part is that the php file must be owned by user joe.

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 you now go to http://localhost/~joe/phpinfo.php, you should see the PHP info page. Should anything go wrong, you can find the error log in /var/log/suphp/suphp.log.

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/
and assume that uploaded_files is meant for administrators' data, not viewable by the public via HTTP.
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!
Last edited by thewanderer on 2010-04-06 08:51, edited 1 time in total.
[url=irc://irc.freenode.net/debian]Find me on #debian at irc.freenode.net[/url] | Linux permission HOWTO | Shorewall firewall | Virtual web hosting

User avatar
bluesdog
Posts: 2077
Joined: 2006-02-01 09:02
Location: Similkameen, British Columbia, Canada
Been thanked: 1 time

Re: suPHP for Apache - multi-user PHP web hosting made easy

#2 Post by bluesdog »

Excellent and clear!

I shall try this tomorrow on a test box

:D

allewi
Posts: 5
Joined: 2010-11-11 10:18

Re: suPHP for Apache - multi-user PHP web hosting made easy

#3 Post by allewi »

Thanks for this detailed step-by-step tutorial. I've read a lot of "professional" tutorials with worse descriptions and instructions, great job! I am relatively new to php web hosting and so this is an interesting thing to test, just want to get some more experience and know-how in php hosting. I'll come back and post in this thread if I have any further questions.

Vanessa13
Posts: 2
Joined: 2011-08-02 09:24

Re: suPHP for Apache - multi-user PHP web hosting made easy

#4 Post by Vanessa13 »

Thank you, it's a very useful and easy thing, nice work :D

unplugme71
Posts: 6
Joined: 2011-08-23 03:12

Re: suPHP for Apache - multi-user PHP web hosting made easy

#5 Post by unplugme71 »

isn't it a bad idea to add users to the group www-data? Can other users run php/apache processes affecting other known users?

thewanderer
Posts: 416
Joined: 2007-03-19 18:11
Location: my desk, Warsaw, Poland

Re: suPHP for Apache - multi-user PHP web hosting made easy

#6 Post by thewanderer »

Hello,
If the permissions are set correctly on all files, then there should be no security risk associated with adding users to group www-data. This measure is only used for sharing static content (html, css, js etc.) with the web server group without exposing it to the rest of machine's users, i.e. non-www users.
It does make the static files readable to every other user on the machine, so it's not suitable for hiding content. However, my assumption was that all static HTTP content is public anyway, and files that are used by scripts (config etc.) are chmodded to 0700.

Since creating this little how-to, I've started writing a Web hosting management framework which manages permissions, among others. It uses POSIX ACL for user www-data instead of groups, so that the files are really only readable by the webserver and nobody else. With proper Apache configuration (follow symlinks if owner match - to mitigate symlink attacks), I believe this is appropriate for storing private static data on the web server without necessarily exposing it to other users on the shared servers.
You can read more about permissions and POSIX ACL here: http://wiki.debian.org/Permissions
Especially note the part about Default ACL - I use it in my hosting development environment to make life easier for users. They don't have to manage permissions, it's possible to just add a default ACL for www-data and an ACL mask (or use a strict default umask in bash/PAM). Masks are a bit tricky, too :P
[url=irc://irc.freenode.net/debian]Find me on #debian at irc.freenode.net[/url] | Linux permission HOWTO | Shorewall firewall | Virtual web hosting

Post Reply