Securing the TMP Partition and Tracking Hacks

Posted by Nessa | Posted in Uncategorized | Posted on 16-11-2007

0

Are your temp partitions putting out behind your back? Anyone who’s ever administered a Linux server would know the risk of leaving the /tmp directory unsecured, moreso on a webserver that is shared among multiple websites.

The tmp directory is world-writeable and used by a majority of services on a machine — including the storage of PHP and MySQL session files. One issue that I’ve seen on older servers is that one customer’s poorly-coded website would get exploited and end up downloading a file into the /tmp directory, then have that hack file executed on the server as a nobody-owned process. Hack processes are the easiest to find, as they always have a little something extra.

This should go without saying, but hack processes can run from almost anywhere, not just /tmp. I’m mainly bringing up the tmp directory because it’s the most targeted location for hack files if it isn’t secured properly.

Identifying Hack Processes

To start out, log into your server as root as issue the following command to see all the nobody-owned processes running on the machine. This is assuming that Apache on your webserver runs as ‘nobody’:

root@localhost[~] ps -efw |grep nobody |more

A majority of the output will reflect legitimate Apache processes:

nobody 8748 25841 0 21:35 ? 00:00:00 /usr/local/apache/bin/httpd -DSSL
nobody 8785 25841 0 21:35 ? 00:00:01 /usr/local/apache/bin/httpd -DSSL
nobody 8988 25841 0 21:36 ? 00:00:00 /usr/local/apache/bin/httpd -DSSL

You’ll see that they all have the same parent process ID of ’25841′ and all of the commands look about the same. However, you may see something that looks like this:

nobody 15707 26407 0 11:18 ? 00:00:00 [sh <defunct>]
nobody 15717 1 0 11:18 ? 00:00:04 /usr/bin/perl
nobody 13016 1 0 14:14 ? 00:00:00 /usr/bin/perl

nobody 8988 1 0 21:36 ? 00:00:00 /usr/local/apache/bin/httpd -DSSL -d3

All of these are hack processes. A few things to look for:

- Perl and shell (sh) processes on most systems run as the user that is executing them, not ‘nobody’. If this is true on your system, a nobody-owned perl process is probably a hack

- The parent ID of the process is different than all the others of the same service — these can be easily faked

- For Apache, an extra little switch on the end of the command (../httpd -DSSL -d3) – ‘d3′ is usually the name of the hack file that is being executed through Apache (not always).

Now I know you probably have the urge to kill -9 it, but don’t. Killing a hack process before determining what it is or where it came from is only going to let it happen again.

Tracking the process:

Once you know which processes should not be running, you need to know where they came from. The *easiest* way to track a process is through the lsof command. If you take the process ID (not the parent) and run an lsof it will tell you everything you want to know:

lsof -p 8748

From here I can see that this process is running from a folder in a user’s account. All I need to do now is kill it off, then remove the hack files from that user’s directory and let them know to update their shit.

TMP Directory Hacks

I’ve seen my fair share, but many hack processes will be spawned from the temp partitions of the server (like /tmp, /tmpDIR, /dev/shm), as these are usually set to 777 to allow programs to store their temporary files. When you first look in your TMP directory you’re going to see a lot of stuff — this is normal, but you’ll want to look for nobody-owned files that stand out. Just a hint, some hacks will try to trick you with their names. I have seen many that are named “…” or “httpd” to make them look legitimate, but I know that httpd (the service that runs Apache) should not be in the tmp directory…and that’s what makes it stand out.

Securing the tmp Partition

I’m not going to go too far into this here, because there’s already a very sexy website with this information available.

If you are on a cPanel server, you should run /scripts/securetmp in addition to following the instructions above.

Installing Mod_Python

Posted by Nessa | Posted in uncategorized | Posted on 11-11-2007

5

Update: These instructions may be outdated for most people. I’ve posted newer instructions on my collaborated sister site:

http://www.thecpaneladmin.com/installing-mod-python-apache-2/

I figured I’d put this out here because it’s come up quite recently with people who are using Apache 1.3.x. If you haven’t gotten the balls to upgrade to Apache 2.x yet, you can still install mod_python…just not as easily. This simple walk through is for Apache 1.x and 2.x.

First, you need to determine what version of Python you are running. To check, type ‘python -V‘ at the command line. If you are running Apache 1.3.x, you should use mod_python version 2.7.11. For Apache 2.2.x, use 3.3.1.

1. Download the Python sources for the version of Python that you have installed, the run a configure and make (no install) just to compile them. If you are running Apache 1.3, you should add –without-threads to your configure line.

2. Once you have this, follow these steps to compile mod_python:

cd /usr/src
wget http://www.trieuvan.com/apache/httpd/modpython/mod_python-2.7.11.tgz
tar -xvzf mod_python-2.7.11.tgz
cd mod_python-2.7.11

./configure –with-apxs=/usr/local/apache/bin/apxs –with-python=/usr/src/Python2.5.5

The –with-python path should reflect the location of the sources you downloaded and compiled earlier.

3. If you are on Apache 1.3, you now need to perform the steps below. If not, skip to step 4:

pico src/Makefile

Locate the ‘CFLAGS’ line, and add the -DEAPI switch so it looks like this:

CFLAGS=$(OPT) $(INCLUDES) -DEAPI

Then add -lutil to the LIBS line like so:

LIBS=-lm /usr/src/Python-2.5.1/libpython2.5.a -lutil

4. Run the make and make install.

5. Now edit httpd.conf and create your handlers. This will tell Apache which file extensions to interpret through mod_python. If you have mod_rewrite installed and enabled, users can override this in their .htaccess files:

LoadModule python_module libexec/mod_python.so
AddModule mod_python.c
AddHandler mod_python .psp .py

Size Matters with PHP

Posted by Nessa | Posted in Uncategorized | Posted on 27-08-2007

0

I figured this might be helpful to post since it seems to be a fairly common issue poking up about PHP’s limits in regard to file size. It’s no secret to fellow programmers that PHP is incapable of readily handling files over 2gb on the typical 32-bit system, but others are easily aggravated with a greeting of errors that look like this:

PHP Warning: ……. failed to open stream: File too large in ……..

Generally I’d say that if you’re trying to get PHP to man-handle huge files you’d need to have one badass server that can take that kind of abuse. Before you go about trying to compile PHP with large file support, you may want to consider passing the ‘split’ command through the system or passthru functions to break your massive files into smaller bits so PHP can handle them. If you’re the type that has to go about everything the hard way, then I guess that’s why you visited my site.
To compile PHP with large file support, you need to add a simple compiler flag preceding your configure statement. This should look as so:

# CFLAGS=”-D_FILE_OFFSET_BITS=64″ ./configure –with-modules-that-i-use

Then your make && make install and (if all goes without error) you should now be able to work with large files with PHP.

Too bad nothing’s really straight forward, eh? Apache itself has a filesize limit too (even up to 2.2.4) so don’t waste your time trying to get your newly-compiled PHP installation to work with Apache. When I was first trying to work this out I figured that it’s best to have two PHP installations, one for Apache and the other just for the CLI.

To do this, create yourself a phpinfo file and copy the configure line, removing the single quotes from around each flag. Two things you’ll want to change though:

  • Remove the ”–with-apxs2=/usr/local/apache/bin/apxs‘ (or similar) flag to keep the installer from compiling against Apache
  • Change your –prefix to a different location. I used ”–prefix=/usr/php-lfs’ .

When the installation is done, make it easier on yourself by creating some symlinks to the new binary:

ln -s /usr/php-lfs/bin/php /usr/bin/php5

ln -s /usr/php-lfs/bin/php /usr/local/bin/php5

This way you have your LFS-compiled PHP version in /usr/bin/php5 to use for your scripts. To call them, you’d use:

php5 /path/to/script or /usr/bin/php5 /path/to/script

What if you actually want to call the script from a browser? Well, you still can’t load a large file in the browser itself, but you can process it through a script to have a process run on the server:

<?php passthru('/usr/bin/php5 myscript.php'); ?>



And that should pretty much do it.

Installing Sphinx for MySQL 5.1

Posted by Nessa | Posted in Uncategorized | Posted on 21-07-2007

18

This is probably one of the two things that drove me crazy over the last two weeks. The first was trying to get cPanel to stop being such a MySQL nazi, the second was getting Sphinx installed into MySQL 5.1 for one of the clients. I’ve installed it with 5.0 on Ubuntu before, but 5.1 with cPanel can be pretty torturous. After talking to the developer who was able to fill in the blanks, I’ve decided to write my own documentation on how to install Sphinx as a dynamic MySQL plugin for an existing MySQL 5.1 installation.

Before we start...

You need MySQL 5.1 installed to use the plugin feature. If you’re running on cPanel or other version-dependent software it’s a really really bad idea to install MySQL from source, so you’ll probably want to read this as a guide to upgrading via RPM. Also, this walkthrough is specific to MySQL 5.1.20 (beta), since that’s the latest release out at the time of this writing.

You also need to have root access, and a decent knowledge of Linux and MySQL.


Download the Sphinx binaries and MySQL 5.1.20 patch:


wget http://sphinxsearch.com/downloads/sphinx-0.9.7.tar.gz
tar -xvzf sphinx-0.9.7.tar.gz
cd sphinx-0.9.7/mysqlse/
wget http://v-nessa.net/imh_files/sphinxse097-mysql5120.patch


patch -p1 < sphinxse097-mysql5120.patch

I should point out that Andrew Aksyonoff (the developer) provided that patch to make Sphinx compatible with MySQL 5.1.20, but you’d probably have to check back on his site for version ugprades and such, esp. for newer versions of MySQL.

Now download the MySQL 5.1 sources — these are only going to be used to compile the Sphinx module:

cd /usr/src
wget http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.20-beta.tar.gz/from/http://mysql.he.net/
tar -xvzf mysql-5.1.20-beta.tar.gz
cd mysql-5.1.20-beta
cp -Rf /usr/src/sphinx-0.9.7/mysqlse/ storage/sphinx

Compile the Sphinx module against the MySQL 5.1 sources, but don’t install:

sh BUILD/autorun.sh
./configure
make

If you look in storage/sphinx/.libs you’ll see the loadable .so files that can plug in to MySQL easily. I suggest you copy them into a more permanent location:

mkdir /var/lib/mysql/plugins
cp storage/sphinx/.libs/ha_sphinx.* /var/lib/mysql/plugins

Now add this line to /etc/my.cnf and restart mysql:

plugin_dir=/var/lib/mysql/plugins

To install, log into the MySQL root and issue the ‘INSTALL PLUGIN’ command:

mysql -u root
mysql> INSTALL PLUGIN sphinx SONAME 'ha_sphinx.so';

To verify its installation, just run the ‘SHOW ENGINES’ command:

mysql> show engines;
| CSV | YES | CSV storage engine
.....
| SPHINX | YES | Sphinx storage engine 0.9.7


If you need further info, check out the doc-u-men-ta-tion.

Upgrading to MySQL 5.1.x on cPanel

Posted by Nessa | Posted in Uncategorized | Posted on 20-07-2007

13

If you have server that run on cPanel, you’ll probably know how big of a Nazi it is in regards to the MySQL versions it can run. We just got this new line of servers at work and one of them I was pretty heartset on installing MySQL 5.1, mainly because of its loadable plugin features where you can install a plugin or module without having to recompile the whole damn thing. Upgrading to 5.1 is easy, you just have to follow the right steps.

First, I would recommend upgrading to cPanel 11 or EDGE, which should have support for compiling Apache with non-supported versions of MySQL. On this server, I’m currently running 11 on the bleeding edge build. Also, it’s a splendid idea to dump all your databases before upgrading.
Note that these instructions mention MySQL 5.1.20-beta because that’s the latest release available at the time of my writing….but you can essentially follow this guide for any version of MySQL!

1. Copy the MySQL libraries from the server into a temporary location:

mkdir /root/sqllibs
cp /usr/lib/libmysqlclient.* /root/sqllibs

2. Find any installed MySQL packages:

rpm -qa | grep -i mysql-

This should present a list of installed rpm’s…remove them with rpm -e ,but note that some may need to be removed before others. Some people also would remove the /var/lib/mysql directory, but you can leave that there.

3. Download and install the MySQL 5.1.x packages:

Hop on over to http://dev.mysql.com/downloads/mysql/5.1.html#linux-x86-32bit-rpms and download the 5.1 RPM’s and install them:

rpm -i MySQL-client-5.1.20-0.glibc23.i386.rpm
rpm -i MySQL-devel-5.1.20-0.glibc23.i386.rpm
rpm -i MySQL-embedded-5.1.20-0.glibc23.i386.rpm
rpm -i MySQL-test-5.1.20-0.glibc23.i386.rpm
rpm -i MySQL-server-5.1.20-0.glibc23.i386.rpm

4. Prepare cPanel

You’ll want to make sure that cPanel’s updates don’t reset the MySQL version, so you need to run the following commands to force cPanel to skip MySQL updates:

touch /etc/mysqldisable
touch /etc/mysqlupdisable

Now edit /var/cpanel/cpanel.config and change the MySQL version to 5.1

Create the symlink:

ln -s /var/lib/mysql/mysql.sock /tmp

Also, verify that the MySQL version is correct by running mysql -V

root@vps [~]# mysql -V
mysql Ver 14.13 Distrib 5.1.20-beta, for pc-linux-gnu (i686) using readline 5.0

5. Set up MySQL

MySQL should have already been started at this point, so you can attempt to log in as root using mysql -u root . If you are able to log in on the first try, great. If not, you’ll need to reset the MySQL password:

pico /etc/my.cnf

Add this line, and restart MySQL

skip-grant-tables


service mysql restart

Now log into MySQL root and set the password:


mysql -u root
mysql> FLUSH PRIVILEGES;
mysql> GRANT ALL PRIVILEGES ON *.* TO root@localhost IDENTIFIED BY 'yourpassword' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;
mysql> exit;

service mysql restart

When you’re done, remove the skip-grant-tables line from /etc/my.cnf and restart MySQL. Then log into Webhost Manager and reset the password *again*… this is necessary to build a bridge between the linux root user and the MySQL root user, so you can log into MySQL both through WHM’s phpMyAdmin, and SSH without a password when logged into the server as root.

All you need to do now is recompile Apache, but move the MySQL libraries back so easyapache can find them:

mv /root/sqllibs/libmysqlclient.* /usr/lib/mysql/

I haven’t tested too many configurations yet, but what works for me is Apache 2.2.4 with php 5.2.3, compiled with MySQL and mysqli, but NOT system MySQL.

Simple MySQL Search Query

Posted by Nessa | Posted in Uncategorized | Posted on 04-07-2007

8

If you use MySQL to keep a ton of records, it might be nice to be able to search for the particular entry you’re looking for via a simple form on your site. To set this up, we’ll make two scripts — one being the form itself, the other being script that executes the MySQL query.

In this example I created a simple form to query a database to look a person’s last name from a database column in an ‘addressbook’ database. First, we need to create the form. This is just a simple html file with a single input field:

<html>
<body>
<h4>Enter Last Name:</h4>
<form action="query.php" method="post">
Server: <input name="lastName" type="text" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Here i named the form field ‘lastName’, which will be the variable passed on to the php script and returned later on, and that the form action is set to ‘query.php’, which is the name of the script processing the form. Next, create a file called query.php:

In the first section we need to define a few database variables to allow the script to connect to the database:


<?php
// Make a MySQL Connection
$dbhost = "localhost";
$dbname = "database_name";
$dbuser = "database_user";
$dbpass = "password";

Next, we need to define the posted variable ‘lastName’, which we created in the form to allow that variable to pass into this script. If you have register_globals turned on (which is a BAD idea), you don’t need to do this.


$lastName = $_POST['lastName'];

Now for actual query itself. The syntax you use to search a database table is as follows:

SELECT <what info> FROM <table> WHERE <column>='<search term'>

So in that case, I want to select everything from the ‘names’ table where the last name is equal to what I search for, denoted by the variable ‘lastName’

$query = "SELECT * FROM names WHERE lastname='$lastName'";

Similarly if you wanted to search two tables in one query you can just use the UNION command like so:

$query = "SELECT * FROM name WHERE lastname='$lastName' UNION SELECT * FROM morenames WHERE lastName='$lastName'

Now that all that crap is defined, create the database link:


$dblink = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db($dbname, $dblink);
?>

Now you can echo the results back into an array (in case there is more than one entry):

<h2> Query Results for <?php echo($lastName); ?> : </h2>
<?php

$result = mysql_query($query) or die(mysql_error());
$row = mysql_fetch_array($result) or die(mysql_error());
while($row = mysql_fetch_array($result)){
echo $row['lastName']. " ", $row['firstName'];
echo "<br />";
}
?>

To explain above, the query is run against the database and the results are fetched as an array. The row(s) contained the search terms are then displayed to the screen based on the colums specified, which in this case are ‘firstName’ and ‘lastName’
In case you’re on the slower end, here’s the entire query.php script:

<?php
// Make a MySQL Connection
$dbhost = "localhost";
$dbname = "database_name";
$dbuser = "database_user";
$dbpass = "password";

$lastName = $_POST['lastName'];

$query = "SELECT * FROM names WHERE lastname='$lastName'";

$dblink = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db($dbname, $dblink);
?>

<h2> Query Results for <?php echo($lastName); ?> : </h2>
<?php

$result = mysql_query($query) or die(mysql_error());
$row = mysql_fetch_array($result) or die(mysql_error());
while($row = mysql_fetch_array($result)){
echo $row['lastName']. " ", $row['firstName'];
echo "<br />";
}
?>

Working with Permissions in PHP

Posted by Nessa | Posted in uncategorized | Posted on 20-06-2007

7

.!.

PHP uses the same command as *nix systems when dealing with changing permissions for files:

chown – changes ownership, but can only be done by a root user
chgrp – changes group ownership, can be done by a user who is a member of the new group
chmod – changes permissions, can be done by the user (and sometimes the group) that owns the file

These commands are particularly useful in situations where PHP runs as a different user on the system, which is common when PHP is compiled as an Apache user. A lot of our customers get frustrated at the fact that once they use PHP to create a file, their user can’t touch it. That’s why whenever you have PHP create a file that needs to be neutral, its permissions have to be set accordingly.

The syntax of those commands are simple:

chown($file, $user)
chgrp($file, $group)
chmod($file, $permissions)

The simplest example of using these commands is a follows:

<?php
$file = "myfile.txt";
$handler = fopen($file, 'w') or die("can't create file");
chmod($file, '0777');
fclose($handler); ?>

In this example, I had the PHP script create a file called ‘myfile.txt’ in write mode, then change its permissions to 777.  This is of course the simplest example in the world, but you can make them much more complex.

For more information on using fopen to handle files, you can read this.  Also, when you set permissions you have to use the octal value (0777) instead of just 777.

Increase Your Blog Traffic

Posted by Nessa | Posted in uncategorized | Posted on 15-06-2007

4

.!.

Yes, it’s another one of those. It seems that every blog has its own tips for increasing traffic, so I decided to add my own tips that seem to have worked for my site

Listing IP Addresses of a Server

Posted by Nessa | Posted in Uncategorized | Posted on 10-06-2007

3

I hate using the jarbled output of ifconfig to find out what ip addresses are active on a server, so using this complex command will list all the IP addresses of the server in a nice little list:

ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'

I specifically use this command for a VPS setup script that I was working on to automatically input the correct server IP into the httpd.conf and named entries on cloned systems, so I don’t have to do it manually. To do this you would just assign the command as a variable, then call that variable with the replace command:

IP=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'`
cat httpd.conf |replace 123.456.789.123 $IP --httpd.conf

If you want to incorporate this into a PHP script, you just need to use the system() function, assuming your host allows it:

<?php system("ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'"); ?>

Installing suPHP on cPanel

Posted by Nessa | Posted in uncategorized | Posted on 05-06-2007

12

.!.

I wrote this tutorial a while back and figured it would be good to post because suPHP is growing more popular as an alternative to phpSuExec. The instructions assume that you are on a Linux cPanel server and are familiar with how to install PHP, but do not want to use EasyApache’s suPHP installer in WHM (you stubborn bitches)

Note also that these instructions use suPHP 0.6.1 with a cPanel patch that makes it equivalent to 0.6.2. I personally have had issues with the actual 0.6.2 version installing, so I stuck with the patch.

Next, download suPHP and the apply the patch:

wget http://v-nessa.net/imh_files/suphp-0.6.1.tar.gz
tar -xvzf suphp-0.6.1.tar.gz
cd suphp-0.6.1

wget http://v-nessa.net/imh_files/suphp-0.6.1-cpanel.patch
patch -p1 < suphp-0.6.1-cpanel.patch

Then compile the binary:

./configure –prefix=/usr –sysconfdir=/etc –with-apxs=/usr/local/apache/bin/apxs –with-apache-user=nobody
make && make install

Now locate your PHP binaries for installation. If you previously used EasyApache, you should be able to find them somewhere in your home directory within a directory named ‘cpeasyapache’ or something similar depending on your cPanel version. Otherwise you will need to fetch the PHP sources from php.net if you do not have the original sources you used to compile.

Check the server’s phpinfo file and grab the configure path, then copy and paste it into notepad and remove all the single quotes. You’re basically compiling PHP exactly the same way as it was before, only not as an Apache module.

cd /home/cpapachebuild/buildapache/php-5.2.3
make clean

The only difference is that you need to remove the ‘–with-apxs=’ switch from the configure line. The prefix can stay the same, but it’s recommended to install this in a different directory, like /usr/cgiphp or something.

So technically your configure would look like this:

./configure –prefix=/usr/cgiphp –with-xml –with-mm ………
make
make install

Now check that the installation was successful (should say cli for this one, but cgi will work as well) :

/usr/cgiphp/bin/php -v

PHP 5.2.3 (cli) (built: Aug 3 2007 07:22:58)
Copyright (c) 1997-2007 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2007 Zend Technologies

Download the suphp.conf into /etc, which is the location you specified during the configuration of suphp:

cd /etc
wget http://v-nessa.net/imh_files/suphp.conf

Now you need to edit /etc/suphp.conf and change the handler paths to (lines 47/48):

x-httpd-php=php:/usr/cgiphp/bin/php-cgi
x-httpd-php5=php:/usr/cgiphp5/bin/php-cgi

Check httpd.conf to see if there is already an suphp module setup in the virtualhost entries. If not, set up the apache template to automatically add it for new accounts:

pico /usr/local/cpanel/etc/httptemplates/apache1/default

Under <IfModule mod_php4.c> (exactly as is) add these lines:

<IfModule mod_suphp.c>
suPHP_UserGroup %user% %user%
suPHP_ConfigPath /home/%user%/php
</IfModule>

suPHP_ConfigPath /home/%user%/php specifies the location of the user’s php.ini file, which will be created later. This is completely optional, as it is only necessary if you want to specify where the users’ php.ini files are going to be location (default location is public_html). Recent versions of cPanel already have an suPHP module loader, so you may only have to add the suPHP_ConfigPath line to the suPHP section.

You should do the same for SSL hosts in /usr/local/cpanel/etc/httptemplates/apache1/ssldefault.

Add the following lines to httpd.conf in their appropriate sections:

LoadModule suphp_module libexec/mod_suphp.so
AddModule mod_suphp.c

<IfModule mod_suphp.c>
suPHP_Engine On
suPHP_ConfigPath /usr/local/Zend/etc
suPHP_AddHandler x-httpd-php5
AddHandler x-httpd-php5 .php5
suPHP_AddHandler x-httpd-php
AddHandler x-httpd-php .php .php3 .php4 .phtml
suPHP_AddHandler x-httpd-php-source
AddHandler x-httpd-php-source .phps
<Files *.php5>
suPHP_ConfigPath /usr/cgiphp/lib
</Files>
</IfModule>

It’s also a good idea at this point to disable the loading of the Apache php module, so they can only run as CGI. Comment out these lines:

#LoadModule php5_module libexec/libphp5.so
#AddModule mod_php5.c

If you do the above, comment out the following lines:

#AddType application/x-httpd-php .php
#AddType application/x-httpd-php .php4
#AddType application/x-httpd-php .php3
#AddType application/x-httpd-php-source .phps
#AddType application/x-httpd-php .phtml

The users that already exist on the system should already have suphp directives in their virtualhost entries. If not, you will need to add them manually:

<IfModule mod_suphp.c>
suPHP_UserGroup user user
suPHP_ConfigPath /home/%user%/php
</IfModule>

In this one you actually need to replace ‘user’ with the username and group of the account.

Now you need to fix the first VirtualHost entry as well, which is the website that is displayed when you go to http://server.com on a shared hosting environment. This is the site that is pulled from /usr/local/apache/htdocs and PHP will not work in this directory, because your suphp.conf file defines the docroot to be /home, meaning that suPHP will not execute PHP that is outside of /home. When you find the VirtualHost container for the main IP add the following into that VirtualHost:

<IfModule mod_suphp.c>
suPHP_UserGroup <user> <user>
<Directory /usr/local/apache/htdocs>
suPHP_GlobalDocRoot /usr/local/apache/htdocs
suPHP_DontCheckVHostDocRoot Yes
</Directory>
</IfModule>

For the user, since PHP won’t execute as nobody or root, this needs to be a valid user on the system. Generally it’s best to create a neutral user on the system with no SSH access to be the owner of the htdocs folder. Whatever user you use, you will need to chown the entire htdocs directory to that user (or whatever directory you use as a default. The DontCheckVHostDocRoot part is necessary if you are running this outside of /home.

Last you should create a php folder in /root/cpanel3-skel with a copy of the server’s php.ini file, so new user accounts are created with a php.ini.

The path to the cgi php binary is /usr/local/bin/php, so you want to make sure that it is accessible when called from command line and that suPHP loads the new binary.

ln -s /usr/cgiphp/bin/php-cgi /usr/local/bin/php
ln -s /usr/cgiphp/bin/php-cgi /usr/local/bin/php5
ln -s /usr/cgiphp/bin/php /usr/bin/php
ln -s /usr/cgiphp/bin/php /usr/bin/php5

If you get an error about one already existing, simple delete it and try to link it again.

Now you have to copy the extentions:

cd /usr/cgiphp/lib/php/
mkdir -p extensions/no-debug-non-zts-20060613

pico /usr/local/lib/php.ini

Change the extension_dir value to that of the new folder you created, then copy all the files over:

cp /usr/local/lib/php/extensions/no-debug-non-zts-20060613/* extensions/no-debug-non-zts-2006061/

Depending on the server, the actual extension directory may be different!

Settings for suphp.conf

Suphp.conf lets you control the settings in place for suPHP. The following settings are the recommended in place for shared servers:

logfile=/var/log/suphp.log

The location of the logfile on the server, will be created automatically.

loglevel=warn

What information to describe in the logs. ‘info’ is very broad, but you can also use ‘warn’ to only show warnings.

webserver_user=nobody

What use Apache runs as — this basically indicates what user no php scripts can run as, even ones in htdocs.

docroot=/home

The base directory where php scripts have to be located in order to run, which prevents php scripts from executing from system folders. If a user for some reason needs to execute something from outside of home, you need to make a virtualhost directive containing:

<Directory /usr/local/apache/htdocs>
suPHP_GlobalDocRoot /<path to directory>
suPHP_DontCheckVHostDocRoot Yes
</Directory>

allow_file_group_writeable=false
allow_file_others_writeable=false
allow_directory_group_writeable=false
allow_directory_others_writeable=false

This is the most important for security, specifying the allowable permissions of files and folders by other users than the one owning the script.

If your server currently has accounts on it, you’ll need to run these followup scripts:

/scripts/postsuexecinstall
/scripts/chownpublichtmls

From /home:

find -perm 777 -exec chmod 755 {} \; -print
find -perm 666 -exec chmod 644 {} \; -print
/scripts/fixsuexeccgiscripts

For the php.ini, you’ll also need to copy it from /usr/bin/php.ini into /home/user/php for all users existing on the machine before the installation of suPHP. New user accounts will automatically have this, as long as it you followed the step of copying it to /root/cpanel3-skel/php

If the server is running Fantastico, make sure you set the config to use phpsuexec.