PHP Logo 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.

  1. 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 (apache or nobody or www-data depending on your Linux distro).

  2. 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.

  3. FastCGI per userFastCGI 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:

  1. mod_php
  2. FastCGI
  3. 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_basedir remains). 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.