Being able to run PHP scripts and applications is probably one of the most obvious feature in shared web hosting today, but the actual process to make it fast and secure at the same time might not be that trivial.
I am actually writing this post in response to this thread at WHT, where web hosts discussed ways to fight back against those 200Gb oversold plans that are populating the shared hosting industry today. That thread went off-topic half way through when Matt Heaton of BlueHost and Kevin Martin of Pair Networks had a not-so-friendly discussion on whether to run PHP as CGI or as mod_php on servers.
Many Ways of PHP
There are many ways to implement PHP on a typical LAMP stack. Let me use a table to illustrate the different methods.
| Methods | mod_php | CGI+suexec | FastCGI/user |
|---|---|---|---|
| Webserver | Apache-only | Many | Many |
| Persistent | Yes | No | Yes |
| Memory (Idle) | High | Low | Medium |
| Memory (Busy) | High | High | High |
| Performance | High | Low | Medium |
| Run as | Apache user | Site owner | Site owner |
| php_value in .htaccess | Yes | No | No |
First of all, we have our 3 contestants.
-
Apache + mod_php — it is by far the fastest way to run PHP scripts, as the PHP interpretor is (1) persistent and (2) in-process. It is also the method most widely adopted by the shared hosting industry. If your site is on a Cpanel account, then it is most likely to be on mod_php.
As PHP is running in-process along-side with Apache, the PHP scripts are running as Apache’s user (
apacheornobodyorwww-datadepending on your Linux distro). -
CGI + SuEXEC — Common Gateway Interface (CGI) is the grand-daddy of dynamic web content, and it is CGI that made scripting languages like Perl popular in the late ’90s. A full PHP interpretor is forked for every request of dynamic content, and process forking is not computationally cheap — at least in the ’90s. This is the very reason why in-process interpretors like mod_php and mod_perl became popular.
One advantage, when combining with Apache’s suEXEC, is that CGIs are running as owner of the scripts, i.e. actual shared hosting users. As the cost of forking is getting relatively cheaper these days, CGI + suEXEC is becoming popular again.
-
FastCGI per user — FastCGI is not a new technology, but because of the popularity of mod_php, it sort of faded in the corner until those new generation frameworks (RoR, Django, etc) brought it back to life again.
In FastCGI, PHP runs externally but persistently, which makes it almost as fast as mod_php. Another advantage is that you can put suEXEC wrappers around it so the persistent FastCGI processes can run as the site owner, instead of a shared FastCGI user.
Now, let us see how our 3 contestants handle two of our problem domains here — security and performance.
Problem Domain 1: Security
The problem of shared web hosting is, everyone (which might be 200+ users on a 4 core Xeon) is sharing the same server on the same file system. It is like you living in the boarding house with 200 other complete strangers. What will be the first thing coming to your mind? How to secure your belongings!!
This would involve:
- No one is allowed to write to a user’s personal space unless explicitly permitted.
- No one is allowed to read from a user’s personal space unless explicitly permitted.
That sounds easy. Don’t all unix have user and group level permission?! The problem is, in the case of mod_php your PHP scripts will need to be readable by the Apache user (apache, nobody or www-data depending on the distro). That means on shared hosting, all users are running the PHP scripts as the same user, and your neighbours will be able to read and write to files that you have created. Worse, as all your PHP scripts, including ones containing sensitive information, must be readable by Apache, someone else on the same server can also read them if they know where to find them!
For example, to steal my neighbour’s WordPress MySQL database password, I would just create a PHP file containing:
<?php
readfile('/home/neighbour/public_html/wp-config.php');
?>
Fortunately the above code is probably not going to work in most shared hosting environment, because of some necessary evils called Safe Mode and related friends. They are PHP-interpretor-level hacks designed for shared hosting environment to prevent the above anti-social behaviour from happening. Side effect? Many scripts no longer work, and many require other hacks to get around this disability.
The scenario is much simpler if the PHP scripts are executed as site owner’s UID. There are many advantages:
- All sensitive files can be changed to mode 0600 so they cannot be read by anyone but the site owner.
- All scripts created files are owned by the site owner, so they can be easily managed in FTP or SSH sessions.
- Process accounting by user would actually work. This is very useful when you need to identify that rogue user who used up all resources on the shared server.
In reality,
- Most users will not know how to change sensitive files to only user-readable. It is more likely that they will change everything to mode 777, because they have read about it from some dodgy online tutorial somewhere.
- How often do scripts need to write to files? You would rather have it writing to a dedicated area, than opening the entire home directory for it to write to.
- If an attacker managed to exploit a buggy PHP code to gain privilege on the webserver, he/she will have that user’s UID instead of Apache server’s. Hosting users usually have more privilege than the Apache user (although it really depends on the setup), which then enables the attacker to do more “things”.
In other words, running PHP as CGI or FastCGI gives security advantage over users on the same shared server, as each user can properly secure his/her own files. Whereas running PHP as mod_php gives security advantage over external attacks, especially when running questionable code.
Problem Domain 2: Performance
If you are bench marking the same script serially again and again, then the answer is obvious. The performance ranking will be:
- mod_php
- FastCGI
- CGI
mod_php has the advantage of being persistent — the PHP interpretor gets initialised and stays in memory, so subsequent requests do not need to go through this initialisation process again. It also has the advantage of being in-process — requests and responses passing between Apache and mod_php are performed merely as memory copy in the same process. FastCGI might be persistent as well, but the communication between the web server and FastCGI slave can either be TCP or unix socket. Neither is as fast as in-process memory copy.
CGI is obviously slower as a new PHP CGI process needs to be built up and teared down for each request. However, the overhead is fixed, and is getting less and less significant when servers are getting faster.
In reality the scenarios will be much more complicated. For example the amount of memory consumed can also be a determining factor on a busy server. The goal would be to serve as much mixed traffic (static + dynamic) without consuming all the memory that puts servers into swapping death.
For example, mod_php only really works in Apache pre-fork MPM, which means every connection held up an Apache process. Lots of connections streaming large media file? Soon you will get too many Apache processes with their 20Mb fully loaded PHP interpretor that swap like crazy.
CGI on the other hand, takes no overhead when idling. It would be very useful for shared hosting business built on top of low-memory VPS, where there might only be a few thousand page views a day.
FastCGI is a different story again. Take mod_fcgid for example, it is one of the most complicated module that requires lots of tinkering. With the default FastCGI configuration, Apache would spawn the PHP FastCGI process when a request comes in. The process will hang around for a while, and will be killed when determined idle timeout is reached. You do not wish to set this idle timeout to be too long, otherwise those PHP FastCGI processes will just sit there, occupy memory and do nothing. But you do not want to set them to be too low either, otherwise Apache might often need to re-spawn the FastCGI processes as previous ones were terminated.
The number of shared hosting account also complicated the picture. Now imagine your shared hosting server has 200 accounts running PHP FastCGI. You set your idle timeout to be the default 5 minutes. Half your accounts are getting one page view at least once every 5 minutes to keep their PHP FastCGI processes alive (damn spiders!!) which means you will have a minimum 100 of them running at the same time, as different users cannot share FastCGI processes. If each process consumes 15Mb RSS, that would be 1.5Gb minimum for all of them combined!
Ouch!
Conclusion
Don’t I love to write a non-conclusive article?! So, mod_php, CGI or FastCGI on shared hosting? It depends.
- mod_php — I think it will continue to be the favourite on the shared hosting servers. Safe mode and friends are annoying, but programmers are getting better working around them. Moreover safe mode is no more in PHP6 (but
open_basedirremains). Just need to watch out for too many Apache processes. - CGI — Great for small servers and VPS with hundreds of clients getting only 50 unique visitors a day. You get the user-level security and low memory utilisation when idling.
- FastCGI — Good for shared hosting with small number of heavy duty users. Each user can run PHP scripts in his/her own UID, and it does not have performance penalties like plain CGI.
Another alternative would be running FastCGI with its own user, so it behaves like mod_php, but you can run Apache with worker MPM to reduce memory footprint.
Obviously the best alternative is not to share server with others. Get a cheap VPS and run mod_php without safe mode, and you do not have to worry about someone else on the server peeking at your files.

12
How does running mpm-itk impact on all of this?
I’m using it, but only on small sites to keep everything separate.
I run each vhost as apache:apache. The user can own the files and thus only make certain files +w to the group apache and as the groups are separate it avoids each of the vhosts to read other files.
I don’t know much about this stuff. I need to read up on how to load test this stuff, but that can come later….
Nicholas — sorry I actually did not know anything about mpm-itk. I just had a look and think it is a good solution. Obviously it has a few issues:
Neither are big issues I think in shared hosting environment. I’ll take a closer look at this stuff.
With regular prefork MPM + mod_php, another user on the same server is running PHP scripts with the same privilege as you. So for every file you enable Apache to read, someone else can read it as well on the same server. chgrp apache + chmod g+w is not that useful as someone else’s script is still running with GID=apache. Explicitly crippling PHP (safe mode + friends) is probably the only secure way for prefork MPM + mod_php.
Umm.
I should have previewed my post, information got chopped off do to angle brackets…
Just to clarify:
I run each vhost as apache:apache(username) (ie apachenorr)
I think everything else makes sense now that the group I run as is not common :)
Another weak spot in many shared environments (using mod_php): the syscall related functions like exec(), passthru(), popen(), proc_open(). Rarely are these excluded from use in php.ini, and especially if safe_mode + safe_mode_exec_dir aren’t set this opens up a can of worms. I am not even sure the backtick operator can be disabled at all if safe_mode=off. (it might though)
To hide sensitive data one might resort to including or fopen-ing remote files (if ISP allows it) which only are served from the proper ip, referer, request_uri etc. Even that’s not secure, since all those details can be spoofed in the header, but combined with a strict firewall ruleset on the second host (e.g. a local machine) most can be kept out. Better than returning an error if the request doesn’t match the criteria would be to return a version of the requested files containing bogus values.
In short: php_mod is not really suited for secure shared hosting. Period.
Nice Article, i’ve always used mod_php with safe mode ON and never had any problems, i guess im lucky with the scripts i choose to use.
Im going to read the “fight back against those 200Gb oversold plans” it looks interesting :p
At the hosting ISP we work at, we use
mod_phpon shared hosting and it’s highly secure. We came up with a way where each user has their own apache instance and anything, whether it bemod_php, server-parsed, etc, are executed as their own unique uid rather than “nobody” or anything shared. I can’t comment on it more, though!!That sounds like mpm-itk which Nicholas has mentioned before…
I thought that. You could chroot everyone yeah? One host I went with did this. that effectively allows multiple apache process’ yeah?
Error in table:
Performance High Medium Low
must be
Performance High Low Medium
Ta. Fixed.
In that “200gb oversold plans” thread, Matt Heaton says if he has an account on your shared server:
“I will be able to not only list every “webable” file for every account on your server…”
Is that possible — and if so actually due to mod_php being installed?
Increase Apache Vhost Security With mpm-itk In RHEL/CentOS 5