# HG changeset patch # User Tomas Zeman # Date 1306137686 -7200 # Node ID 222d58b81cedd12d52d98e388b667389bad4274c # Parent f712e7140d1cf31315f0070b2046ba7768223b38 lighttpd/virtual-hosting-individual-php: each virt. host runs php under own uid diff -r f712e7140d1c -r 222d58b81ced lighttpd/virtual-hosting-individual-php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lighttpd/virtual-hosting-individual-php Mon May 23 10:01:26 2011 +0200 @@ -0,0 +1,403 @@ +http://redmine.lighttpd.net/projects/1/wiki/HowToSetupFastCgiIndividualPermissions + +1. Add users to the operating system + +(This is only needed if you haven't added users yet.) + +You must add a user account to the operating system for each user that you want +to give separate user permissions, in order to deny access to other users' +source code. + +2. Add user groups to the operating system + +You need to add one user group for each user added above. To keep things +simple, we just name the user groups similar: + +Now you need to add users to each of these user groups. For each user group, +there must be two members: the corresponding user and the lighttpd daemon user. + +You configure the user groups by editing /etc/group with your favourite text editor. + +The file must look something like this (group numbers may vary): + +..... [lots of stuff above] +fred:x:441:fred,lighttpd +george:x:442:george,lighttpd +ron:x:443:ron,lighttpd + +You might also use a sed command like this: + +sed -i "s/^\(fred.*\)$/\1,fred,lighttpd/g" /etc/group +sed -i "s/^\(george.*\)$/\1,george,lighttpd/g" /etc/group +sed -i "s/^\(ron.*\)$/\1,ron,lighttpd/g" /etc/group + +These commands add the user and the lighttpd user to the groups. + +3. Set up filesystem structure + +Let's assume that you want to keep all files associated with the web-server's +virtual hosts under the directory ''/var/www''. (Of course you can choose +another location, just make sure that the users created above have read and +execute rights to the directory. (I.e. ''chmod 755 /var/www && chown root:root +/var/www''). + +3.1 Create server root directory + +Now, create two directories: One for some start-up scripts that only root have +access to, and another for all your virtual hosts: + +#!ShellExample +# cd /var/www +# mkdir fastcgi +# mkdir vhosts +# chown lighttpd:lighttpd * +# chmod 755 * + +# ls -l /var/www + +drwxr-xr-x 2 lighttpd lighttpd 4096 Feb 15 12:17 fastcgi +drwxr-xr-x 9 lighttpd lighttpd 4096 Feb 15 11:21 vhosts + +3.2 Create a directory for each virtual host + +Now create a directory for each virtual host in the directory +''/var/www/vhosts'', and set up appropriate user rights to them: + +#!ShellExample +# cd /var/www/vhosts +# mkdir fred-weasley.com +# mkdir george-weasley.com +# mkdir ron-weasley.com +# chown fred:fred fred-weasley.com +# chown george:george george-weasley.com +# chown ron:ron ron-weasley.com +# chmod 750 * + +# ls -l /var/www/vhosts + +drwxr-x--- 7 fred fred 4096 Feb 15 20:18 fred-weasley.com +drwxr-x--- 6 george george 4096 Feb 15 11:02 george-weasley.com +drwxr-x--- 6 ron ron 4096 Feb 15 11:23 ron-weasley.com + +Now we have created three directories where the three users cannot see each +others' files; however, the lighttpd daemon user can see it all. + +3.3 Create directory structure for each virtual host + +Now, we want to create the directory struture needed for each virtual host: + +#!ShellExample +# cd /var/www/vhosts/fred-weasley.com +# mkdir html +# mkdir includes (optional) +# mkdir logs +# chown fred:fred * +# chown lighttpd:fred logs +# chmod 750 * + +# ls -l /var/www/vhosts/fred-weasley.com + +drwxr-x--- 14 fred fred 4096 Feb 17 11:55 html +drwxr-x--- 2 fred fred 4096 Feb 15 12:05 includes +drwxr-x--- 2 lighttpd fred 4096 Feb 15 11:11 logs + +You need to repeat this for each virtual host, replacing the user name +'fred' with the appropriate user name. + +3.4 Create a FastCGI directory for each user + +Now we have to do all the fun stuff! + +Now, go to the ''/var/www/fastcgi'' directory where we want to create a +directory for each user. (When we're finished, these directories will hold the +sockets to the FastCGI server processes): + + +#!ShellExample +# cd /var/www/fastcgi +# mkdir fred +# mkdir george +# mkdir ron +# chown fred:fred fred +# chown george:george george +# chown ron:ron ron +# chmod 750 * + +# ls -l /var/www/fastcgi + +drwxr-x--- 7 fred fred 4096 Feb 15 20:18 fred +drwxr-x--- 6 george george 4096 Feb 15 11:02 george +drwxr-x--- 6 ron ron 4096 Feb 15 11:23 ron + +(Note that the lighttpd user can read all directories, while the three users +can only access their own directory.) + +4. Create a FastCGI start-up script for each user + +Create a directory that will hold all your FastCGI start-up scripts: + +#!ShellExample +# cd /var/www/fastcgi +# mkdir startup +# chmod 750 startup + +# ls -l /var/www/fastcgi + +drwxr-x--- 7 fred fred 4096 Feb 15 20:18 fred +drwxr-x--- 6 george george 4096 Feb 15 11:02 george +drwxr-x--- 6 ron ron 4096 Feb 15 11:23 ron +drwxr-x--- 6 root root 4096 Feb 15 11:23 startup + +Now, go to the ''/var/www/fastcgi/startup'' directory, create a start-up script +for fred (let's call it fred-startup.sh, using your favourite text editor: + +#!sh +#!/bin/sh + +## ABSOLUTE path to the spawn-fcgi binary +SPAWNFCGI="/usr/bin/spawn-fcgi" + +## ABSOLUTE path to the PHP binary +FCGIPROGRAM="/usr/bin/php-cgi" + +## bind to tcp-port on localhost +FCGISOCKET="/var/www/fastcgi/fred/fred.socket" + +## uncomment the PHPRC line, if you want to have an extra php.ini for this user +## store your custom php.ini in /var/www/fastcgi/fred/php.ini +## with an custom php.ini you can improve your security +## just set the open_basedir to the users webfolder +## Example: (add this line in you custom php.ini) +## open_basedir = /var/www/vhosts/fred/html +## +#PHPRC="/var/www/fastcgi/fred/" + +## number of PHP childs to spawn in addition to the default. Minimum of 2. +## Actual childs = PHP_FCGI_CHILDREN + 1 +PHP_FCGI_CHILDREN=5 + +## number of request server by a single php-process until is will be restarted +PHP_FCGI_MAX_REQUESTS=1000 + +## IP adresses where PHP should access server connections from +FCGI_WEB_SERVER_ADDRS="127.0.0.1" + +# allowed environment variables sperated by spaces +ALLOWED_ENV="PATH USER" + +## if this script is run as root switch to the following user +USERID=fred +GROUPID=fred + +################## no config below this line + +if test x$PHP_FCGI_CHILDREN = x; then + PHP_FCGI_CHILDREN=5 +fi + +export PHP_FCGI_MAX_REQUESTS +export FCGI_WEB_SERVER_ADDRS +export PHPRC + +ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS PHPRC" + +# copy the allowed environment variables +E= + +for i in $ALLOWED_ENV; do + E="$E $i=$(eval echo "\$$i")" +done + +# clean environment and set up a new one +env - $E $SPAWNFCGI -s $FCGISOCKET -f $FCGIPROGRAM -u $USERID -g $GROUPID -C $PHP_FCGI_CHILDREN + +chmod 770 $FCGISOCKET + +Please be careful with the paths, USERID and GROUPID. + +Note that, in this example, the php process runs as the user we created above +('fred'). This means that the php code will have write access to the html and +php files. This can be convenient, but might be a security risk. +Alternatively, you could set USERID to 'nobody' (or any other user without any +specific permissions), to deny write access to the php process. + +You need to repeat the process and create a startup-script for each user in the +''/var/www/fastcgi/startup'' directory. (Just copy the file and replace +FCGISOCKET, USERID and GROUPID with the correct values). + +Remember to set execute permissions on all your startup-scripts: + + +#!ShellExample +# cd /var/www/fastcgi/startup +# chmod 750 * + +5. Check your PHP configuration + +If you're uncertain about the location of your php.ini, just run the following +command: + + +#!ShellExample +$ php-cgi -i | grep php.ini +Please check, that you have the following line in your php.ini: + + +cgi.fix_pathinfo=1 + +If you have uncommented the PHPRC line in the shell script under issue 4., be +sure that the php.ini has the correct owner an rights. To get things work this +must be + +chmod 644 php.ini +chown root:root php.ini + +6. Execute all FastCGI start-up scripts + +Now, fire up all your FastCGI server processes: + +#!ShellExample +# /var/www/fastcgi/startup/fred-startup.sh +spawn-fcgi.c.170: child spawned successfully: PID: xxxxx +# /var/www/fastcgi/startup/george-startup.sh +spawn-fcgi.c.170: child spawned successfully: PID: xxxxx +# /var/www/fastcgi/startup/ron-startup.sh +spawn-fcgi.c.170: child spawned successfully: PID: xxxxx + +If you get any error messages, please re-check your startup-scripts and the +permissions to the ''/var/www/fastcgi'' directory, including all user +sub-directories. + +7. Configure virtual hosts in the lighttpd server + +Edit ''/etc/lighttpd.conf'' in your favourite text-editor: + + +.....[lots of configuration stuff above]..... + +$HTTP["host"] =~ "(^|\.)fred-weasley.com$" { + server.document-root = "/var/www/vhosts/fred-weasley.com/html" + accesslog.filename = "/var/www/vhosts/fred-weasley.com/logs/access_log" + fastcgi.server = ( ".php" => + ( + ( "socket" => "/var/www/fastcgi/fred/fred.socket", + "broken-scriptfilename" => "enable" + ) + ) + ) +} + +$HTTP["host"] =~ "(^|\.)george-weasley.com$" { + server.document-root = "/var/www/vhosts/george-weasley.com/html" + accesslog.filename = "/var/www/vhosts/george-weasley.com/logs/access_log" + fastcgi.server = ( ".php" => + ( + ( "socket" => "/var/www/fastcgi/george/george.socket", + "broken-scriptfilename" => "enable" + ) + ) + ) +} + +$HTTP["host"] =~ "(^|\.)ron-weasley.com$" { + server.document-root = "/var/www/vhosts/ron-weasley.com/html" + accesslog.filename = "/var/www/vhosts/ron-weasley.com/logs/access_log" + fastcgi.server = ( ".php" => + ( + ( "socket" => "/var/www/fastcgi/ron/ron.socket", + "broken-scriptfilename" => "enable" + ) + ) + ) +} + +Please note the paths to the FastCGI sockets for each virtual host. + +'''server.errorlog is NOT working in conditionals, all errors go to the last +logfile specified. So just use one global error log.''' + +8. Restart the lighttpd daemon process + +Simply run this command: + +#!ShellExample +# /etc/init.d/lighttpd restart +If you get any errors, please re-check your ''/etc/lighttpd.conf'' configuration file. + +9. Hello World! + +Now, log in as the user fred and create a PHP script file in his virtual host +(e.g. ''/var/www/vhosts/fred-weasley.com/html/index.php''): + + +#!php +Hello World!"; +echo "

Current User ID is: ". posix_getuid(); +echo "

Current Group ID is: ". posix_getgid(); +?> +Also, make sure to set the file permissions: + + +#!ShellExample +# chown fred:fred /var/www/vhosts/fred-weasley.com/html/index.php +# chmod 640 /var/www/vhosts/fred-weasley.com/html/index.php + +# ls -l /var/www/vhosts/fred-weasley.com/html + +-rw-r----- 1 fred fred 116 Jul 25 2004 index.php + +Now fire up your web-browser and check the output of your PHP script. (Here: +http://www.fred-weasley.com/index.php) + +If everything went well, you will see an output showing the User ID of the user +fred, and the Group ID of the user group fred. (You can see these IDs in the +files ''/etc/passwd_ and _/etc/group''). + +10. Automatically start the FastCGI startup scripts + +Optionally, you may also create a crontab entry to automatically execute the +FastCGI startup scripts when your server boots. + +Use the following command to edit your crontab: + + +# crontab -e +Now add the following line: + + +@reboot for i in /var/www/fastcgi/startup/*.sh; do $i; done +And finally type ":x" to save and exit. + +This crontab entry will execute all .sh files found in the +/var/www/fastcgi/startup directory after the server has booted. + +Congratulations! You now have a working fast server configuration with +individual (separate) user rights. + +Limitations + +Using this model you are creating a separate pool of fastcgi processes for each +user. This means that no memory will be shared between these processes. +Therefore, if you use this model for a machine with a large number of users you +will need a significant amount of available RAM. Also, if you use any PHP +opcode cache such as xcache, apc or eaccelerator, this model means that each +user will get their own dedicated cache (which is a good thing from a security +perspective, but bad for memory usage). You can tailor the memory used by +having different php.ini files that configure the accelerator with differing +cache sizes, and by altering the value of PHP_FCGI_CHILDREN in each user's +startup.sh script. + +In FreeBSD (6.2) every user can be in a maximum of 14 groups. This is the upper +bound for webhost-fastcgi-instances, as your lighty-user (www) needs access to +those sockets. I installed my webhost 1-2 years ago in this way and run in +trouble a few weeks ago while adding www to it's 15th group. No error-msg gaves +a hint. Go, and google for it. By the way: Is there a solution? ;) - Yes, +FreeBSD 8.0 will raise this limitation to 1024. + +Permissions + +mod_fastcgi has an option: check-local. When enabled, Lighty uses his user to +check if the file exists in document-root. If you want Lighty's user to not +have access to the document-root, this option must be disabled. +