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?).
- One
/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 separatephp.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 apublic_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):
ServerName someuser.somedomain DocumentRoot /var/www/vhosts/someuser/public_html SuexecUserGroup someuser someuser FcgidWrapper /var/www/vhosts_config/someuser/wrapper-bin/php .php #max of 5 cgis per vhost FcgidMaxProcessesPerClass 5 FcgidMinProcessesPerClass 0 AddHandler php-fcgi .php Action php-fcgi /wrapper-bin/php Alias /wrapper-bin/ /var/www/vhosts_config/someuser/wrapper-bin/ Options +ExecCGI SetHandler fcgid-script
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:
export PHPRC=/var/www/vhosts_config/someuser/php export PHP_INI_SCAN_DIR=$PHPRC/ext-active/ export PHP_FCGI_CHILDREN=0 umask 0077 exec /usr/bin/php-cgi
PHP_INI_SCAN_DIR
sets a directory to look for additionalphp.ini
files, which I use for loading extension-specific configuration.PHPRC
lists the directory in which to find thephp.ini
file.
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).
manpreet
Best Answer
2 years ago
I'm a sysadmin for a small server at my university, which is used by students to experiment and run long jobs at their will.
I enabled PHP in user directories so they could experiment with websites and all with some comfort.
Recently, I realized that all PHP code in user directories are run by the web server user (www-data) which has some privileges that I obviously don't want to give to the users. A vulnerable site or malicious user could delete the server's regular website.
Is there a way to run user's PHP with the user's privileges?
I thought of a workaround to this that is giving the webserver almost zero privileges so a breach into it could not compromise anything serious. This is doable in my situation since the website is very very simple (plain html index).
The server is running Debian Jessie with Apache 2.4.10.