I have done this a number of times using nginx, lighttpd, and apache. The concept is basically the same in all of them: [Fast]CGI processes that run as the user.
If you want to save yourself a lot of trouble, try messing with permissions as other people have suggested. In particular, if your user websites are owned by the users and your main site is owned by root or similar, you will be in decent shape. But users will still not be segregated and could read eachother's files etc (database passwords?). Running separate virtual servers for each user/site will give you the most security, and it is certainly simpler than trying to segregate users with apache.
The standard accepted way of segregating PHP users in apache is via SuExec (there is also mpm-itk). If you Google for
apache fastcgi suexec or similar, you should get plenty of results. I think it would be impractical to include full directions here. It can vary based on various design decisions and the distribution in use. Instead, I will try to provide some points I consider important and a brief description of my configuration. My setup gets pretty complicated (and on top of this, I run a custom SELinux module). Here is a [hopefully] brief overview:
- Name based virtual hosts by pointing *.somedomain to the server: user.somedomain is the name of the virtual host (I assume you could do the same thing with user directories?).
/etc/httpd/vhosts.d/user.conf for each user.
- One directory in
/var/www/vhosts_config for each user.
/var/www/vhosts_config/$USER/wrapper-bin contains the wrapper to execute PHP (more on this later)
/var/www/vhosts_config/$USER/php/php.ini: I like to have a separate
php.ini per user.
/var/www/vhosts_config/$USER/php/ext/*.ini: One ini file per available extension
/var/www/vhosts_config/$USER/php/ext-active/*.ini: symbolic links back to
../ext for each enabled extension (so I can enable/disable extensions per user too)
/var/www/vhosts/user contains the actual content for the vhost. I recommend always using a
public_html subdirectory as the document root so users have a directory that is outside of the document root to store configuration files etc.
- Users should not be able to read each other's files. You need to allow the webserver
+x on the users'. There are a variety of ways you could do this. I use POSIX ACLs.
The per-user httpd config looks something like this (altered for brevity):
SuexecUserGroup someuser someuser
FcgidWrapper /var/www/vhosts_config/someuser/wrapper-bin/php .php
#max of 5 cgis per vhost
AddHandler php-fcgi .php
Action php-fcgi /wrapper-bin/php
Alias /wrapper-bin/ /var/www/vhosts_config/someuser/wrapper-bin/
suexec is a
setuid root program that apache invokes to start processes as a given user. It is pretty fussy. It requires that the program it executes is owned by the user and contained in a subdirectory of
/var/www (this varies on different Linux distributions and is set at compile time) directory that is owned by the user. This is why each user needs his own PHP wrapper script.
/var/www/vhosts_config/someuser/wrapper-bin/php looks something like:
PHP_INI_SCAN_DIR sets a directory to look for additional
php.ini files, which I use for loading extension-specific configuration.
PHPRC lists the directory in which to find the
You do not have to use a separate PHP configuration for each user, and doing so certainly complicates things. I like to give users a stripped down configuration and enabled only what is necessary (and a few common extensions by default). I also load suhosion with different configurations for each user (different encryption keys).