To configure apache for a single domain is easy. To configure apache with multiple virtual hosts for a single webmaster is easy, too.
But if you need to host several domains for several different users this can be much more difficult. The biggest problem is to offer PHP functionality while keeping the system secure and fast.
====== Scenario ======
* One server, many users and one or more domains for each user.
* The users should be able to use php-scripts for their webpages.
* A user must not be able to access data from other users.
* php-scripts should be able to use system tools so that applications like gallery or a CMS will work.
====== Problem ======
* php scripts will be executed with privileges of the user apache is running as. This is bad because then every user can access the same data including the home directories of any user.
====== Possible solutions ======
===== mod_chroot =====
Ths apache module [[http://core.segfault.pl/~hobbit/mod_chroot/|mod_chroot]] can be used to chroot() an apache process into a virtual hosts DocRoot.
Disadvantages:
* system tools have to be copied into every chroot because the apache process can access nothing more that its own DocRoot.
* This can mean much work for the admin.
* It uses more diskspace
* It will complicate TPE (trusted path execution) or makes it unpossible to use reducing system security
* chrooting to a vhost only works with the Apache2 module
===== PHP safe_mode =====
The [[http://de2.php.net/features.safe-mode|PHP safe_mode]] may be used to tell PHP to not allow access to files not owned by the same user as the script itself, restrict several php functions such as system() exec() fopen() etc.
Disadvantages:
* opening files owned by the user is not possible if apache is still running as a different user
* using system wide php classes or libraries is not possible because they are not owned by the user
* some php applications may not work anymore
===== suPHP =====
With [[http://www.suphp.org/Home.html|suPHP/mod_suphp]] any php script is executed with uid of the owner of the script.
Disadvantages:
* for every http request a new php-cgi process will be started through the suphp wrapper which will do set(e)uid()/set(e)gid() before serving the request. This makes it terrible slow. It will work for a page with a low number of hits, but high traffic webpages will be too slow and it will kill your webservers performance.
===== mod_become =====
Using [[http://www.snert.com/Software/mod_become/index.shtml|mod_become]] there is no need for suPHP anymore making it possible to use mod_php instead of php-cgi. It will setuid()/setgid() the apache process before serving a request.
Disadvantages:
* Slow as suPHP
* Static html pages are slow, too
* Apache must be recompiled with -DBIG_SECURITY_HOLE
====== Conclusion so far ======
If its secure and fast, it has limitations. If it is secure and has no limitations, its slow.
Now what? Impossible to do that? Wait. There might be another solution:
====== **The** solution? ======
===== mod_fastcgi =====
This module can be used to pre-fork cgi processed and let them running instead of starting up a new process for every request.
[[http://www.debianhowto.de/howto-archiv/de/apache2-phpfcgi-sarge/c_apache2-phpfcgi-sarge.html|Apache2, php5-fcgi, php4-fcgi, mod_fastcgi HowTo]] (german)
====== Benchmarking ======
For testing we install apache and all other needed stuff into a default debian sarge chroot.
Hardware:
Intel(R) Celeron(R) CPU 2.00GHz with 512MB of RAM
===== Preparation =====
We use a tool called [[http://hammerhead.sourceforge.net/|hammerhead]] to stress our apache.
The tool [[http://www.vanheusden.com/httping/|httping]] will be used to test apache's response time
Benchmarking with hammerhead:
I tried to find a hammerhead config that will get most out of the webserver, but will not stress the hammering machine too much.
There are two different scenarios:
* for static pages
NStatic HTML page
RGET /static/ HTTP/1.0
Etestpagethis is a test
* for php pages
NDynamic page (PHP)
RGET /php/ HTTP/1.0
Etestpagethis is a test
The corresponding testpages will be created like that:
- cd /var/www/
/var/www# mkdir static php
/var/www# echo "testpagethis is a test" > static/index.html
/var/www# echo "testpagethis is a test