Can You Secure A Shared Server With PHP + FastCGI?

Posted by Stuart Herbert @ 8:29 AM, Tue 07 Oct 08

Filed under: 3 - Advanced, The Web Platform

13 Comments

The challenge with securing a shared hosting server is how to secure the website from attack both from the outside and from the inside. PHP has built-in features to help, but ultimately it s the wrong place to address the problem.

I’ve already written about a number of solutions that work, but one option I’ve been asked time and time again to look at is using PHP + FastCGI. The belief is that using FastCGI will overcome the performance issues of Apache’s suexec or mod_suphp, because FastCGI processes persist between page views.

But before we can look at performance, the first question is: how exactly do we get PHP and FastCGI running as different users on the one web server in the first place?

Installing And Configuring mod_fcgid for Apache

Stock Apache does not ship with built-in support for FastCGI. You need to download and install a third-party module. There are two choices – the original mod_fastcgi, and the more recent mod_fcgid, which I’ll look at in this article. Before we start, make sure that you have built and configured Apache to use suexec. We will reuse suexec to ensure that our FastCGI PHP processes run as different users.

Most Linux distributions already include a package for mod_fcgid; you should be able to install it using your distro’s package manage. The version I’ve tested for this article is mod_fcgid 2.2 running on Seed Linux (a Gentoo-based distro).

After installing mod_fcgid, make sure that you edit your Apache config files, and comment out any lines that load mod_php. They will look like this:

LoadModule php5_module modules/libphp5.so

Then, add the following lines to your virtual host.

SuexecUserGroup myuser mygroup

<Directory /var/www/localhost/htdocs>
AddHandler fcgid-script .php
Options ExecCGI
Allow from all
FCGIWrapper /var/www/localhost/cgi-bin/php.fcgi .php
</Directory>

Replace “myuser” with the user who owns the website, and replace “mygroup” with the group that the user belongs to. This sets the privileges that PHP will run as when this website is visited.

Because suexec is understandably paranoid about what CGI programs it will run for you, to make mod_fcgid work in a shared hosting environment, we need to create a FastCGI wrapper script owned by the same user that owns the website:

#!/bin/bash
PHPRC=/etc/php/apache2-php5
export PHPRC
PHP_FCGI_CHILDREN=4
export PHP_FCGI_CHILDREN
PHP_FGCI_MAX_REQUESTS=5000
export PHP_FCGI_MAX_REQUESTS
exec /usr/lib/php5/bin/php-cgi

Each website needs its own copy of the script. Place this script in the website’s dedicated cgi-bin directory. This should be a directory that you control to make sure that malicious scripts cannot be uploaded to take advantage of suexec. Make sure that the script is owned by the user and group who owns the website, otherwise suexec will refuse to run the script, and you’ll spend quite a bit of time scratching your head wondering what the problem is!

The FastCGI wrapper script gives us an opportunity to set limits on how PHP works as a FastCGI process. We can tell it how many FastCGI scripts are allowed to run (to make sure one website doesn’t use up all of the web server’s free capacity), and also how many HTTP requests each FastCGI process should handle before terminating (to limit the impact of memory leaks).

At this point, you can restart Apache, and you should find that your websites are now using suexec + FastCGI to run as separate users.

Making Apache Go Even Faster

One of the major benefits of using Apache 2.2 over Apache 1.3 is the ability to switch how Apache works at the fundamental level. Apache MPMs (multi-processing modules) can emulate Apache 1.3’s behaviour (mpm-prefork) … but it can also provide new options. By default, most (if not all) Linux distributions install Apache 2.2 built with mpm-prefork, but by switching to another MPM, can we make our websites go even faster?

If you are using suexec + mod_fcgid on Linux, there are two MPMs available to you that have the potential to boost performance further: mpm-worker and mpm-event. Both MPMs turn Apache into a multi-threaded server. On Linux systems, it is usually much quicker to create new threads than it is to create new processes. The downside is that software has to be specially written to work correctly in a multi-threaded application (known as being thread-safe). mod_php doesn’t work reliably with mpm-worker and mpm-event, because it reuses a lot of third-party code that may or may not be thread-safe. But because we’re running PHP in a separate FastCGI process, we can safely turn Apache into a multi-threaded server.

Some Benchmarks

To benchmark PHP + FastCGI + suexec, I used Apache s ab benchmark to load a simple phpinfo() page 1,000 times. I ran the benchmark five times, and averaged the results. To compare the results, I repeated the tests against mpm-worker, mpm-event, and mpm-prefork both with and without mod_php.

  • mpm-worker + mod_fcgid + PHP/FastCGI + suexec: 7.36 seconds, 0.2% failure rate
  • mpm-event + mod_fcgid + PHP/FastCGI + suexec: 7.75 seconds, 0.2 % failure rate
  • mpm-prefork + mod_fcgid + PHP/FastCGI + suexec: 7.92 seconds, 0.2% failure rate
  • mpm-prefork + mod_fastcgi + PHP/FastCGI + suexec: 8.52 seconds, 0.2% failure rate
  • mpm-prefork + mod_php: 7.38 seconds, 0% failure rate

Other Considerations

The performance is good, especially if you switch Apache MPMs. These benchmarks are extremely simplistic, and what they don’t show is that switching to mpm-worker and mpm-event will probably speed up your websites even further, because these Apache MPMs handle downloading images more efficiently than mpm-prefork can. You may also be able to scale your websites better before having to upgrade your servers or add additional ones, especially if you use a bytecode cache such as APC or xcache.

But what are the downsides?

  • As with straight suexec, you can’t use HTTP authentication in your application. Hardly any apps rely on this functionality any more (probably because so many shared hosting servers use suexec).
  • Your server may require extra RAM to cope with the number of FastCGI processes running simultaneously. You may need to switch to a 32-bit Linux kernel that supports PAE or to a 64-bit Linux distro.
  • Apache + PHP/FastCGI is not 100% reliable in my testing.

Conclusions

It is possible to combine PHP, FastCGI and suexec to produce a solution that secures a shared hosting server and at the same time provides good performance compared to the alternatives. If you’re prepared to compile Apache from source and switch MPMs, you can squeeze even more performance from this combination, and perhaps even out-perform the venerable mod_php.

Unfortunately, my experience was that the PHP + FastCGI combination cannot be trusted to serve pages 100% of the time. The average failure rate was 2 requests per 1000, and the failure rate was consistent no matter which Apache MPM was used, which Apache FastCGI module was used, and how many thousands of requests I used in my testing. At the time of writing, I haven’t tracked down the cause of this failure, and it may not appear in your own environment, but none of the previous solutions I’ve looked at in this series have displayed this problem, so it’s something to think about before chosing PHP + FastCGI to serve your websites. I’m hoping to find time in the future to get to the bottom of this problem, if no-one gets there first.

As a result, I can’t recommend using PHP/FastCGI + suexec at this time. My current recommendation is mpm-itk, which has successfully served millions of page hits for me in production over the last few months.

References

This article was made possible by information already on the internet:

This article is part of The Web Platform, an on-going series of blog posts about the environment that you need to create and nurture to run your web-based application in. If you have any topics that you d like to see covered in future articles, please leave them in the comments on this page.

13 comments »

Using mpm-itk To Secure A Shared Server

Posted by Stuart Herbert @ 1:00 PM, Sat 19 Apr 08

Filed under: The Web Platform

Tags: , , , , ,

21 Comments

The challenge with securing a shared hosting server is how to secure the website from attack both from the outside and from the inside. PHP has built-in features to help, but ultimately it s the wrong place to address the problem. Apache has built-in features too, but the performance cost of these features is prohibitive.

This has created a gap that a number of third-party solutions have attempted to fill. One solution you may have heard of is mpm-itk, by Steinar H. Gunderson. How well does it work, and how well does it perform?

  • mpm-itk: Running Apache As A Specified User
  • Installing mpm-itk
  • Configuring Apache
  • Some Benchmarks
  • Other Considerations
  • Conclusions

mpm-itk: Running Apache As A Specified User

Like mpm-peruser, mpm-itk is an alternative multi-processing module (MPM) for Apache 2.x. It also allows each website’s PHP scripts to run as a separate user. But the main difference is that it doesn’t maintain separate pools of processes for each user. Instead, after the PHP request has completed, each process is terminated, and new processes must be created to handle new requests.

Until I researched mpm-itk for this article, I didn’t realise that it didn’t recycle processes after each request. This means that there’s no chance at all of it matching mpm-peruser for performance (something I suggested was possible), but that doesn’t mean that mpm-itk is entirely without merit.

Installing mpm-itk

mpm-itk needs to be compiled into your Apache installation. It cannot be loaded as a module.

First of all, download the Apache source code, and then download either the mpm-itk patch for Apache 2.0, or the mpm-itk patch for Apache 2.2. For this article, I’m going to focus on Apache 2.2, but the same instructions should apply for Apache 2.0.

Unpack the Apache source code, apply the mpm-itk patch, and rebuild Apache’s build scripts:

$ mkdir -p /tmp/apache-itk
$ cd /tmp/apache-itk
$ wget http://www.mirrorservice.org/sites/ftp.apache.org/httpd/httpd-2.2.8.tar.gz
$ wget http://mpm-itk.sesse.net/apache2.2-mpm-itk-20080105-00.patch
$ tar -zxf httpd-2.2.8.tar.gz
$ cd httpd-2.2.8
$ patch -p1 < ../apache2.2-mpm-itk-20080105-00.patch
$ autoconf

Then, configure the Apache source code to build with mpm-itk as the chosen MPM. Make sure that you run configure with any other configuration switches that you need:

$ ./configure --with-mpm=itk

After that, compile and install Apache:

$ make ; make install

Configuring Apache

mpm-itk is very easy to configure. For each of your virtual hosts, simply add the AssignUserId entry:

<VirtualHost *:80>
ServerName www.example.com
...

<IfModule mpm_itk_module>
AssignUserId stuart stuart
</IfModule>
</VirtualHost>

AssignUserId takes two parameters:

  • The first parameter is the user ID to run Apache under for this website.
  • The second parameter is the group ID to run Apache under for this website.

Remember to restart Apache after adding AssignUserId, and you should be all set.

Some Benchmarks

To benchmark mpm-itk, I used Apache s ab benchmark to load a simple phpinfo() page 1,000 times. I ran the benchmark five times, and averaged the results.

  • mpm-itk: average of 37.01 seconds
  • mpm-prefork: average of 6.21 seconds

mpm-itk benchmarks much better than suexec and suphp, but is still quite a bit slower than mpm-peruser.

Other Considerations

It isn’t just about performance. Both suexec and suphp bring limitations to your PHP applications, but mpm-itk does not. Because mpm_itk puts the job of switching users in the right place – at the heart of Apache – it allows your code to run under mod_php. As a result, your code is free to take advantage of any Apache features that aren’t available to PHP/CGI, such as HTTP authentication support.

Another consideration is the impact on RAM and CPU. Whilst you can definitely use mpm-peruser to provide a faster solution, it does involve a lot of effort in tuning the size of the process pools for each of the websites on a shared server. On a shared hosting server, you can’t necessarily find one tuned configuration that always suits demand – and it may not be worth your time to put the effort in anyway. Although mpm-itk is slower, it doesn’t need tuning for each individual website. It’s more of a fire-and-forget solution that might appeal to hosting providers who don’t know (and don’t really need to care) what your customers websites are.

Conclusions

Although it needs to be compiled from source, mpm-itk provides the security of suexec and suphp with much greater performance than either of these solutions. Although it performs worse than mpm-peruser, mpm-itk doesn’t require as much effort to configure and tune for best performance, and its greater simplicity probably makes it better suited to shared hosting servers running a random collection of websites.

mpm-itk is an option that you should seriously consider when designing your shared hosting server solution.

This article is part of The Web Platform, an on-going series of blog posts about the environment that you need to create and nurture to run your web-based application in. If you have any topics that you d like to see covered in future articles, please leave them in the comments on this page.

21 comments »

The challenge with securing a shared hosting server is how to secure the website from attack both from the outside and from the inside. PHP has built-in features to help, but ultimately it s the wrong place to address the problem. Apache has built-in features too, but the performance cost of these features is prohibitive.

This has created a gap that a number of third-party solutions have attempted to fill. One solution you may have heard of is mpm-peruser, by Telana Internet Services. How well does it work, and how well does it perform?

  • A Bit of History
  • Installing mpm-peruser
  • Configuring Apache
  • Some Benchmarks
  • Other Considerations
  • Conclusions

(more…)

1 comment »

Have Any Other Shared Hosting Solutions For Me To Look At?

Posted by Stuart Herbert @ 12:27 PM, Sun 20 Jan 08

Filed under: The Web Platform

5 Comments

I’ve been working my way through the different solutions available for securing a shared hosting server. So far, I’ve looked at:

The solutions that are left on my todo list are:

Are there any other solutions for securing shared hosting that you know about, and would like me to include? If there are, let me know by leaving a comment below.

5 comments »

Using suphp To Secure A Shared Server

Posted by Stuart Herbert @ 8:10 AM, Fri 18 Jan 08

Filed under: The Web Platform

21 Comments

The challenge with securing a shared hosting server is how to secure the website from attack both from the outside and from the inside. PHP has built-in features to help, but ultimately it s the wrong place to address the problem. Apache has built-in features too, but the performance cost of these features is prohibitive.

This has created a gap that a number of third-party solutions have attempted to fill. One of the oldest of these is suphp, created by Sebastian Marsching. How well does it work, and how well does it perform?

  • suphp: Running PHP As A Specified User
  • Installing suphp
  • Configuring Apache
  • Some Benchmarks
  • Other Considerations
  • Conclusions

suphp: Running PHP As A Specified User

Like Apache’s own suexec, suphp is a solution that allows PHP to run as the user and group that owns any particular website on a shared hosting server.

suphp consists of two components:

  • mod_suphp, an Apache module that replaces mod_php
  • suphp, a setuid binary that replaces Apache’s suexec

It relies on PHP/CGI having been installed onto the server first.

Installing suphp

suphp is compiled and installed in the same way as any other Apache module. These instructions are for Apache 2.2, but they will work fine for Apache 2.0 as well. (You can run suphp on Apache 1.3 too). (Gentoo Linux and Seed Linux users can skip these instructions; you can install suphp using ‘emerge mod_suphp‘).

Download the suphp source code from the website. Unpack the tarball somewhere, like this:

tar -zxf suphp-0.6.2.tar.gz
cd suphp-0.6.2

Next, run the configure script:

./configure --with-setid-mode=paranoid
    --with-min-uid=1000
    --with-min-gid=100
    --with-apache-user=www
    --with-logfile=/var/log/apache2/suphp_log
    --with-apxs=/usr/sbin/apxs
    --with-apr=/usr/bin/apr_config

You’ll need to adjust some of these settings to suit your local operating system:

  • –with-min-uid sets the lowest user id that PHP is allowed to run as. Check your /etc/passwd file to see just how low this needs to be set.
  • –with-min-gid sets the lowest group id that PHP is allowed to run as. Check your /etc/group file to see just how low this needs to be set.
  • –with-apache-user tells suphp which user Apache will be running as.
  • –with-logfile tells suphp where to write log messages to. I recommend that you configure suphp to write its logfile in the same directory that Apache would normally write its log files.
  • –with-apxs tells suphp where to find the Apache util that’s used to help build Apache modules.
  • –with-apr tells suphp where to find the Apache Portable Runtime (apr) config util.

It’s worth pointing out that there are several different options to choose from for the –with-setid-mode config. Check out the suphp documentation (included in the source tarball) for the details on what each mode does.

Next, run make to compile the software.

Assuming everything compiles just fine, the next step is to install mod_suphp by copying it to your Apache modules directory:

cp  src/apache2/.libs/mod_suphp.so /usr/lib/apache2/modules/

After that, you need to install the suphp binary:

cp src/suphp /usr/sbin/suphp
chmod 4755 /usr/sbin/suphp

mod_suphp is hard-coded to expect the suphp binary to be installed into /usr/sbin. If you put it anywhere else, mod_suphp won’t be able to run PHP for you!

To finish, download the suphp configuration file from Gentoo’s CVS, and install it as /etc/suphp.conf. Then, edit the file, updating all the settings to match the values you passed to the configure script.

Configuring Apache

The first thing you need to do to your Apache config files is to comment out mod_php. mod_suphp is a replacement for mod_php; you cannot run both at the same time.

Then, in your main httpd.conf file, add the following:

LoadModule suphp_module modules/mod_suphp.so
AddType application/x-httpd-php   .php
AddHandler application/x-httpd-php .php

suPHP_Engine On

<Location />
SuPHP_AddHandler x-httpd-php
</Location>

DirectoryIndex index.php index.htm index.html default.htm default.html

This tells Apache to load mod_suphp, to associate it with PHP scripts, and to look for index.php et al when a URL only specifies a folder name instead of a file.

The final step is to go into each of your virtual hosts, and tell mod_suphp which user owns the virtual host. This will the user and group that PHP will run as.

<VirtualHost www.example.com>
SuPHP_UserGroup stuart mybusiness
</VirtualHost>

Now you’re ready to restart Apache and to run some tests to make sure that suphp is up and running.

Some Benchmarks

suphp works the same way as Apache’s suexec. Every time a PHP script is run, suphp has to fork Apache and then execute another copy of the PHP/CGI binary. This approach provides the absolute security benefits that we seek, but is much slower than using mod_php.

To benchmark suphp, I used Apache’s ab benchmark to load a simple phpinfo() page 1,000 times. I ran the benchmark five times, and averaged the results.

  • suphp: average of 164.677 seconds
  • mod_php: average of 6.422 seconds

suphp is some 25 times slower than mod_php. This is a substantial performance hit, but it’s better than suexec, which benchmarked at 36 times slower than mod_php. I admit to being surprised that suphp performs better than suexec; I plan to put all of the alternatives covered here in a “head to head” article soon!

Other Considerations

One neat feature of suphp is that it can support both PHP 4 and PHP 5 running on the same box at the same time. Hopefully, you’ve already made the move to PHP 5 and you don’t need this feature – but it’s there if you do.

The same feature can be used to support both PHP 5 and PHP 6 (when it’s released) at the same time.

Be aware that the last release of suphp was in 2006. There is an active mailing list you can join for community help and support.

Conclusions

suphp is an easy-to-install, easy-to-configure and easy-to-maintain alternative to Apache’s own suexec. If you are running a shared server and the horrific performance penalty doesn’t put you off, then suphp is well worth looking at instead of using suexec.

But the question is – is there anything better out there, something that provides both security and performance? In the next article, I’ll take a look at a third-party Apache mod that attempts to answer that.

This article is part of The Web Platform, an on-going series of blog posts about the environment that you need to create and nurture to run your web-based application in. If you have any topics that you d like to see covered in future articles, please leave them in the comments on this page.

21 comments »
Next Page »

Categories

Archives

What's Stu Doing Now?