Learn More About PHP And The Web Platform!

Struggling with your web server, or to scale your PHP application to meet growing demand?

Whether you're running one server or a whole server farm; whether you're hosting on Windows Server or on Linux.

Learn from Stuart's experience with system design, delivery, support and management to help you do a better job and have an easier time.

Beneath Whitby breakwater

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 »

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.

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

So what can Apache do to help?

It turns out that there are quite a few alternative ways that Apache can help. This article will look at what we can do with stock Apache, and the next few articles will look at what we can do with some interesting third-party Apache modules.

  • suexec: Running CGI Programs As A Specified User
  • Configuring Apache With PHP/CGI
  • Configuring suexec With PHP/CGI
  • Configuring suexec For Shared Servers
  • Some Benchmarks
  • Other Considerations
  • Conclusions

suexec: Running CGI Programs As A Specified User

To secure a shared hosting server, we want to be able to run PHP as the user who owns that particular website. One way to do this with stock Apache is with suexec.

suexec is a standard Apache module which allows you to run a CGI executable as a specified user and group. CGI executables date back to the very early days of the web, back when we all had to use Perl to create dynamic websites. Although PHP is commonly run as an Apache module, it still provides support for CGI.

Check with your Linux vendor to make sure that you have PHP/CGI installed on your box.

Configuring Apache With PHP/CGI

The first step for getting suexec working is to configure Apache to run PHP as a CGI executable, instead of using mod_php. Add the following configuration to your httpd.conf file:

ScriptAlias /php5-cgi /usr/bin/php-cgi
Action php5-cgi /php5-cgi
AddHandler php5-cgi .php
AddDirectoryIndex index.php

… and add the following line to your virtual host:

AddHandler php5-cgi .php

In your httpd.conf file (or in one of the files that httpd.conf includes), there will be a <Directory> entry for the directory on disk where your virtual host is stored. Inside that <Directory> entry, there should be an “Options” line, which might look like this:

Options Indexes FollowSymLinks

Add “ExecCGI” to the end of your Options line.

Make sure to comment out mod_php from Apache. Then, restart Apache, and do some testing to make sure that PHP 5 is working.

For reference, here is the Apache config from my test system:

ScriptAlias /php5-cgi /usr/bin/php-cgi
Action php5-cgi /php5-cgi
AddHandler php5-cgi .php
AddDirectoryIndex index.php index.phtml

<VirtualHost *:80>
        DocumentRoot /var/www/localhost/htdocs
        <Directory /var/www/localhost/htdocs>
                Options Indexes FollowSymLinks ExecCGI
                AllowOverride All
                Order allow,deny
                Allow from all
       </Directory>
        AddHandler php5-cgi .php
</VirtualHost>

Configuring suexec For PHP/CGI

With Apache now running PHP as a CGI executable, we’re ready to get Apache running PHP as the owner of each website.

In your test virtual host, add the following:

SuexecUserGroup stuart users

Replace “stuart” with the user who owns the website, and replace “users” with the group that the user belongs to. This sets the privileges that PHP will run as.

To ensure the security of your server, suexec is very particular about what conditions must be met before it will execute your PHP scripting engine. A full list of conditions can be found in the Apache docs. To make sense of the conditions, you’ll need to know what settings your copy of suexec has been compiled with. Run the command suexec -V to find out your system’s settings. This is the output from my Seed Linux LAMP Server system:

belal vhosts.d # suexec -V
 -D AP_DOC_ROOT="/var/www"
 -D AP_GID_MIN=100
 -D AP_HTTPD_USER="apache"
 -D AP_LOG_EXEC="/var/log/apache2/suexec_log"
 -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
 -D AP_SUEXEC_UMASK=077
 -D AP_UID_MIN=1000
 -D AP_USERDIR_SUFFIX="public_html"

The first condition (and one that isn’t obvious from the Apache manual!) is that the PHP CGI executable must be installed under AP_DOC_ROOT. Chances are that it isn’t installed there at the moment, so go ahead and copy it there.

mkdir /var/www/localhost/cgi-bin
cp /usr/bin/php-cgi /var/www/localhost/cgi-bin

The second condition is that the PHP CGI executable must be owned by the same user and group you listed in the SuexecUserGroup statement earlier. This causes problems for shared hosting; I’ll show you how to fix that later in this article.

chown stuart users /var/www/localhost/cgi-bin/php-cgi

Update your Apache httpd.conf file to use this copy of PHP:

ScriptAlias /php5-cgi /var/www/localhost/cgi-bin/php-cgi

Restart Apache, and test to make sure that PHP 5 is still working. You should also start to see log messages appearing in AP_LOG_EXEC. This is the first place to look if PHP isn’t working (although the log messages can be a little terse and cryptic).

For reference, here is the Apache config from my test system:

ScriptAlias /php5-cgi /var/www/localhost/cgi-bin/php-cgi
Action php5-cgi /php5-cgi
AddHandler php5-cgi .php
AddDirectoryIndex index.php index.phtml

<VirtualHost *:80>
        DocumentRoot /var/www/localhost/htdocs
        <Directory /var/www/localhost/htdocs>
                Options Indexes FollowSymLinks ExecCGI
                AllowOverride All
                Order allow,deny
                Allow from all
        </Directory>
        SuexecUserGroup stuart users
        AddHandler php5-cgi .ph
</VirtualHost>

Configuring suexec For Shared Servers

I mentioned earlier that there was a problem with using suexec + PHP/CGI on shared servers – the very environment where suexec is needed the most :( In one of the steps above, we created a copy of the PHP CGI executable, and changed its ownership on disk to match the ownership of the website.

chown stuart users /var/www/localhost/cgi-bin/php-cgi

What happens when we have two websites, each owned by a different user? Or five, or ten, or hundreds? Apache’s suexec will refuse to re-use this copy of the PHP CGI executable for each of the websites, because it isn’t owned by the right user and group.

Each website needs its own copy of the PHP CGI executable, owned by the user and group that owns the website itself. We don’t want to create hundreds of copies of the actual PHP CGI executable (it’s a large waste of space, and a pain for managing PHP upgrades), so instead we can point each website at its own copy of a simple bash script:

#!/bin/bash

/usr/bin/php-cgi "$@"

This script simply executes our central copy of the PHP CGI executable, passing through whatever parameters Apache has called the bash script with.

To configure Apache to use this script, simply move the ScriptAlias statement from outside the VirtualHost config to inside.

Some Benchmarks

Because Apache is having to execute a new suexec process every page hit (and suexec executes a new PHP CGI process every page hit), it’s going to be slower than running mod_php. But how much slower? To find out, I used Apache’s ab benchmarking program to load a phpinfo() page 1000 times. I ran the benchmark five times and averaged out the results.

  • suexec: average of 127.219 seconds
  • suexec + bash script: average of 134.836 seconds
  • mod_php: average of 3.753 seconds

suexec on its own is some 34 times slower than using mod_php; suexec + the bash script needed for shared hosting environments is even worse, at 36 times slower than using mod_php.

This benchmark doesn’t provide the full picture. Once you take into account the extra memory used by the suexec method, and the extra memory and CPU (and process context switches!) required to transfer output from PHP/CGI to Apache to send back to the website’s user, the final cost of using suexec + PHP/CGI will be substantially higher.

Other Considerations

Performance isn’t the only thing to think about when evaluating suexec + PHP/CGI.

  • suexec + PHP/CGI does solve the security challenge, without requiring your application to support safe_mode.
  • HTTP authentication is only supported by mod_php, not PHP/CGI. If your application relies on this, then suexec + PHP/CGI is not for you.

Conclusions

Apache’s suexec mechanism does secure a shared hosting server from attack from within. However, this is achieved at a heavy performance cost, which inevitably will translate into needing lots of extra servers – which is expensive.

So, if Apache itself doesn’t come with a solution that’s worth a damn, maybe there are third-party solutions out there that can do a better job? The next article in the series will take a look at what others have done to try and plug this gap.

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.

19 comments »

I’m still working on the next article in my series looking at PHP on servers, so in the mean time, check out this simple way to emulate Ruby’s nice way of handling separate getter, setter and state query methods in PHP:

class Example
{
	private $canCache = false;
	private $cacheXml = null;

	function canCache($newState = null)
	{
		// check if we are querying or changing state
                if ($newState === null)
 		{
 			// we are querying
 			return $this->canCache;
 		}

  	 	// if we get here, we are a traditional getter/setter method
 		if ($newState)
 		{
 			$this->canCache = true;
 			$this->cacheXml = $this->_toXml();
 			return true;
 		}
 		else
 		{
 			$this->canCache = false;
 			unset($this->cacheXml);
 			return false;
 		}
 	}
}

$exObj = new Example();
$exObj->canCache(true);
if ($exObj->canCache())
{
 	// ... do something here
}

It isn’t as elegant as Ruby, but it does the job, and it means that your classes don’t have to be full of seperate canDoSomething() and isSomethingAllowed() type methods. I think it makes the code that uses the object a little easier to read, and a little more intuitive. YMMV.

13 comments »

Anyone Using Textmate To Work With PHP?

Posted by Stuart Herbert on November 30th, 2007 in Toolbox.

My editor of choice for PHP for the last year or two has been phpEclipse. It’s the best compromise so far between IDE-like features (especially being able to search the entire code base, being able to have multiple projects open at once, and the absolute best class/function inspector in any PHP editor I’ve used so far – I can’t live without these features) and a text editor with acceptable performance (which is where Zend Studio has always lost out; can’t abide an editor that can’t keep up with my typing), syntax highlighting and code layout.

Unfortunately, phpEclipse doesn’t get released all that often (the last official release was 18 months ago now, although there are nightly CVS builds for folks who can afford to risk a broken PHP dev environment, and unfortunately I can’t afford that in my day job). That’s a long time to go without bug fixes and useful new features! It also suffers from that annoying Eclipse-ism of being unable to do anything for 10 minutes or so when you first open a project, whilst the workspace is rebuilt.

So I’m currently auditioning Textmate to see whether it can replace phpEclipse as my environment of choice. First impressions are pretty favourable (it supports projects, its fast, and the syntax highlighting is close enough) but it seems to lack a few useful features that phpEclipse has (like a class inspector – grrr, and being able to use phpdoc to provide context-sensitive help) and the performance seems to suck something awful when working on remote filesystems over 100mbit ethernet.

I was wondering if anyone else who reads Planet PHP has switched to Textmate, and if you’ve got any tips you can share on how to make Textmate a great PHP editing environment. If you do, please leave a comment below.

25 comments »
Page 31 of 34« First...1020...2930313233...Last »

This Month

July 2014
S M T W T F S
« Jan    
 12345
6789101112
13141516171819
20212223242526
2728293031  

Recent Comments