spareknet.org
Customized CPanel Solutions / Server Administration

Home
suphp on CPanel Published on September 6th, 2006 Last Modified on: September 8th, 2008

Note: This guide requires a lot of modification to the suPHP code and modifications to the CPanel template system. I have been running this in a testing production environment for almost a year and I have not noticed any problems with this. That being said, you really should just follow this at your own risk. I believe this method to be safe, but I can only verify the problems that I see, and I haven’t seen any. That doesn’t mean that there aren’t any problems, it just means that I’m not aware of any.

I have provided a patch that does most of the dirty work listed here. You can download it below.

Note: This guide is meant for Apache 1.3. I am of the understanding that suPHP is available in easyapache in Edge at the time of this writing, but I believe it is only for Apache 2. I’m also of the understanding that there are problems with this installation.

Note: This guide applies to suPHP version 0.6.1. If a new version of suPHP has been released, then this guide may or may not work.

Update September 11, 2006 Some questions have been raised concerning the PHP source handler and the php-source.sh script. You won’t find me arguing for it. I am just stating what I collected off of the suPHP mailing list. Whether its secure or not, its up to you. I will concede that its probably questionable at best. But it should also be noted that its not necessary. All it gives you is pretty syntax highlighting of PHP source code in files that use a .phps file extension. If you have no desire to offer this or are concerned about the security of this feature, then feel free to skip that part.

Update January 8th, 2006 More information concerning suphp can be found at the suphp mailing list. There is also an archive at this link which has all of the old mailing list posts.

This guide is meant for fresh servers. Servers that do not have any VirtualHosts on them. You can still apply this to servers that already have accounts on it, but you will need to modify each VirtualHost to contain the necessary directives. If you only have a couple of accounts, this may be more feasible.

1. Download suPHP
This seems obvious enough. You need a copy of the suPHP source so that you can make the necessary modifications and install it. You can download suPHP from its website. suPHP is developed by Sebastian Marsching.

After you download suPHP, extract it:

tar -zxf suphp-0.6.1.tar.gz

 

2. Fix mod_suphp.c
A common problem with suPHP appears to be in the mod_suphp.c file. I’m not entirely sure why this is the case, but it seems that this always has to be fixed.

Change:

suphp-0.6.1/src/apache/mod_suphp.c (Line 252)
{“suPHP_AddHandler”, suphp_handle_cmd_add_handler, NULL, ACCESS_CONF,

To:

{“suPHP_AddHandler”, suphp_handle_cmd_add_handler, NULL, RSRC_CONF|ACCESS_CONF,

Then make another modification to the same file.

Change:

suphp-0.6.1/src/apache/mod_suphp.c (Line 254)
{“suphp_RemoveHandler”, suphp_handle_cmd_remove_handler, NULL, ACCESS_CONF,

To:

{“suphp_RemoveHandler”, suphp_handle_cmd_remove_handler, NULL, RSRC_CONF|ACCESS_CONF,

 
3. Apply mod_suphp.patch
Now you are ready to start applying the necessary suPHP patches. The first patch mod_suphp.patch is part of the patching processes necessary for executing PHP scripts outside of the suPHP docroot, which is explained later. Basically, this is necessary in order to get PHP to work for host.name.com on your server, where PHP execution takes place in /usr/local/apache/htdocs. The patches are in the download section at the bottom of this guide.

You need to be in the suphp-0.6.1/src/apache directory to execute this patch and obviously the path to mod_suphp.patch depends on where you placed the patch file.

cd suphp-0.6.1/src/apache
patch -p0 < mod_suphp.patch

 
4. Apply Application.patch
Now apply the Application.patch patch. This patch is again part of the process of changing suPHP to execute PHP code outside of suPHP’s docroot.

You need to be in the suphp-0.6.1/src directory to execute this patch.

cd suphp-0.6.1/src
patch -p0 < Application.patch

This now gives you access to two new suPHP directives, suPHP_GlobalDocRoot and suPHP_DontCheckVHostDocRoot.
 
5. Apply suphp-0.6.1-userdir.patch
This patch allows you to execute PHP code using http://ip/~username/test.php. In this example, the PHP script will be executed as username. This means that users can access their website via IP (on a shared IP environment) and PHP will still execute as their username. This is also useful if you have a shared secure certificate set up on your server, since users can still access their account through the secure server and as their username.

To apply this patch you need to be in the parent suphp-0.6.1 directory.

cd suphp-0.6.1
patch -p1 < suphp-0.6.1-userdir.patch

 
6. Modify the mod_suphp.c file
Now you need to modify the suphp-0.6.1/src/apache/mod_suphp.c for some additional changes.

Change:

suphp-0.6.1/src/apache/mod_suphp.c (Line 565)
apr_table_setn(r->subprocess_env, “SUPHP_URI”, apr_pstrdup(p, r->uri));

To:

ap_table_setn(r->subprocess_env, “SUPHP_URI”, ap_pstrdup(p, r->uri));

 
7. Modify the Application.cpp file
Now you need to modify the suphp-0.6.1/src/Application.cpp file.

Change:

suphp-0.6.1/src/Application.cpp (Lines 216-218)
if (config.getCheckVHostDocroot()
          && realScriptFile.getPath().find(environment.getVar(“DOCUMENT_ROOT”))
          != 0) {

To:

if (config.getCheckVHostDocroot()
          && realScriptFile.getPath().find(environment.getVar(“DOCUMENT_ROOT”))
          != 0 && !config.getHandleUserdir()) {

 
8. Modify the mod_suphp.c file
This is the last file modification. In this modification, I am going to disable the suPHP_ConfigPath from being used in users .htaccess files. If users want to bypass a php.ini directive, I want to know about it. With this disabled, if a particular user needs a PHP directive changed, they will have to have the server administrator customize a php.ini for them and then reference this in the httpd.conf file. This is explained in more detailed near the end of this guide.

Change:

suphp-0.6.1/src/apache/mod_suphp.c (Line 339)
{“suPHP_ConfigPath”, suphp_handle_cmd_config, NULL, OR_OPTIONS, TAKE1,

To:

{“suPHP_ConfigPath”, suphp_handle_cmd_config, NULL, RSRC_CONF|ACCESS_CONF, TAKE1,

At this point, you have made all of the necessary code changes. You can archive the suphp-0.6.1 directory and have a copy of the necessary patches and modifications to the code and you can just deploy this to any and all servers, without having to make the modifications again.

I did create a patch file that takes in consideration all of this patching. It is in the downloads section below. To apply this patch simply run:

cd suphp-0.6.1
patch -p1 < suphp-0.6.1-cpanel.patch

I did want to show all of the necessary steps that are required to get this far, in case you wanted to make further modifications.

 

9. Compile suPHP
Now you are ready to compile the suphp binary and apache module. The configure line that I give below is the one that I use and I believe it to be correct for most CPanel servers, but again yours may vary. You need to be in the suphp-0.6.1 directory when issuing these commands.

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

 
10. Compile a CGI PHP binary
It is important to note that you need to compile a CGI PHP binary. You can basically compile PHP in one of two ways, either as a CGI binary or as a CLI (Command Line Interface) binary. Both execute code in a similar manner, but are different. suPHP needs a CGI binary to work properly. I recommend that you compile a CGI PHP binary separately, to keep it independent of CPanel and to know where it is.

It really doesn’t matter what configure line you use, just as long as it compiles. The key thing to note is that you use –prefix and –disable-cli and make sure that you do not use a –with-apxs. Below is a configure line from one of my servers. Its just given as an example, you should use whatever PHP configure you desire.

./configure ‘–prefix=/usr/cgiphp’ ‘–with-xml’ ‘–enable-bcmath’ ‘–enable-calendar’ \
‘–with-curl’ ‘–enable-ftp’ ‘–with-gd’ ‘–with-jpeg-dir=/usr/local’ \
‘–with-png-dir=/usr’ ‘–with-xpm-dir=/usr/X11R6’ ‘–with-gettext’ \
‘–with-imap=/usr/local/imap-2004g’ ‘–enable-mbstring’ ‘–enable-mbstr-enc-trans’ \
‘–enable-mbregex’ ‘–with-mcrypt’ ‘–with-mhash’ ‘–enable-magic-quotes’ \
‘–with-mysql=/usr’ ‘–enable-sockets’ ‘–with-ttf’ ‘–with-freetype-dir=/usr’ \
‘–enable-gd-native-ttf’ ‘–with-zip’ ‘–with-zlib’ ‘–enable-force-cgi-redirect’ \
‘–disable-pear’ ‘–disable-cli’
make

make install

The above configure line will compile a CGI PHP binary in /usr/cgiphp/bin. Verify that this is indeed a CGI PHP by:

/usr/cgiphp/bin/php -v

This should report the PHP version as being cgi as opposed to cli.

PHP 4.4.4 (cgi) …

 
11. Create suphp.conf file
suPHP needs a configuration file that it reads from. This defines certain aspects of suPHP and includes what PHP binaries are applied to what Apache Handlers. This is what allows you to run concurrent PHP versions or PHP installations on the same server. I have included my sample suphp.conf file in the download section below. The key thing to note in this file is that the section labeled [handlers]. The handlers defined need to point to CGI PHP binaries for that specific handler. The handlers come into play when we edit the httpd.conf file.

The suphp.conf needs to be placed in the /etc directory. This is defined by the –sysconfdir=/etc parameter in the suphp configure line when compiling suPHP.
 
12. Edit VirtualHost template
This is the one part of this guide that is questionable. This involves editing the VirtualHost template to accommodate suPHP. I’m not sure when or if the template is ever replaced by CPanel. This is also why this guide is really only intended for fresh server installs. Once you make this modification, any future account you create on the server will be ready to use suPHP, but this will not apply to any current VirtualHosts already existing on the server.

You will need to edit the file on your server at /usr/local/cpanel/etc/httptemplates/apache1/default.

/usr/local/cpanel/etc/httptemplates/apache1/default (after Line 9) Add:
<IfModule mod_suphp.c>
suPHP_UserGroup %user% %user%
</IfModule>

The %user% is not representing anything special, it should be copy directly. The %user% is interpreted by CPanel during account creation to mean the username of that specific account that was created. The suPHP_UserGroup is necessary for suPHP to run properly. It tells the server what user to run the PHP script as.

Note: It should be noted that this only affects creation of regular VirtualHosts and does not work with SSL VirtualHosts. I did not make any modifications to the SSL VirtualHost template, but I suppose you could. It is located at /usr/local/cpanel/etc/httptemplates/apache1/ssldefault. If you do not make any modifications to the ssldefault template then when you create an SSL account, then it will not function properly. The respective suPHP_UserGroup directive will need to be added to that VirtualHost. I do not have a lot of SSL VirtualHosts and do not create a lot and I never got around to testing if this was possible. I’m assuming that it just requires the same modifications to the ssldefault file, but I never tested it so I’m not including it here.
 
13. Set up php-source.sh
Update September, 11 2006 – Some security issues have been raised concerning this. This step is not mandatory. You can safely disregard this step, and it will have no effect on regular PHP execution on your server. It will only affect PHP source files, in that they will not be syntax highlighted.

This is a relatively recent finding I found on the suphp mailing list. It came to the attention that .phps files were not being parsed with suPHP. This was somewhat minor, since I’m not aware of any of my clients using .phps files and I just really don’t think there are a lot of people that use .phps (PHP Source Files) files. Never-the-less, I did incorporate this into the guide and this seems to work fairly well.

In the suphp.conf file that I gave as an example, you will see the line:

x-httpd-php-source=php:/usr/cgiphp/php-source.sh

This is the handler that tells Apache to pass php-source files (.phps) to this shell script. The php-source.sh is given below in the download section, but I will also give its contents here.

You need to create the file /usr/cgiphp/php-source.sh

/usr/cgiphp/php-source.sh
#!/bin/sh
echo “Content-type: text/html”
echo “”
/usr/local/bin/php -s $SCRIPT_FILENAME

Remember how suPHP required a CGI PHP binary. Well in this particular instance, PHP has to be a CLI binary. So /usr/local/bin/php needs to a CLI version of PHP. I think this is the default install for PHP on CPanel, so this should be the case. But you can again verify this by running:

/usr/local/bin/php -v

This time you want it to say cli in the top line and not cgi.

Now you want to set this file so that it can execute on the server.

chmod 755 /usr/cgiphp/php-source.sh

This means that you have to maintain two different versions of PHP. You have to maintain a CGI version of PHP and a CLI version of PHP. You really should maintain a copy of CLI PHP anyway, in case anyone is using PHP in their crontabs. You want users to use the CLI version of PHP when executing PHP from the command line or through crontabs.
 
14. Set up httpd.conf file
The final step in this process is making the appropriate adjustments to the httpd.conf file, so that Apache knows to parse PHP through the suPHP binary.

You will need to open the /etc/httpd/conf/httpd.conf file for editing. When you open that file, look through the file or search for the section that contains several LoadModule directives. I’ve noticed that in some instances these lines are already added. I’m sure its something that I have done that causes the discrepancies, but the point is, these two lines need to be present in your httpd.conf file. If this line does not already exist, at the bottom of that list add:

LoadModule suphp_module       libexec/mod_suphp.so

The next section immediately following the LoadModule section will be the AddModule section. At the end of that list, if it does not already exist, add:

AddModule mod_suphp.c

Now scroll down through the httpd.conf file or search for the area where it defines file extensions for PHP parsing. I think the section usually contains the 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
AddHandler cgi-script .cgi .pl
AddType text/html .shtml
AddType application/x-tar .tgz
AddType text/vnd.wap.wml .wml
AddType image/vnd.wap.wbmp .wbmp
AddType text/vnd.wap.wmlscript .wmls
AddType application/vnd.wap.wmlc .wmlc
AddType application/vnd.wap.wmlscriptc .wmlsc

Below that section add:

<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/cgiphp5/lib
</Files>
</IfModule>

Updated September 11, 2006 Again security concerns regarding the php-source.sh method have been raised. If you elected not to set up the php-source.sh script and do not want to go through with the PHP source set up, then you can leave out or comment out the lines:

suPHP_AddHandler x-httpd-php-source
AddHandler x-httpd-php-source .phps

If you leave them out, it will not adversely affect any other PHP functions.

To explain some of the directives listed here see below:

Now you need to fix the first VirtualHost entry so that PHP is parsed correctly here. This is the website that is displayed when you go to http://mainip on a shared hosting environment. The contents of this website is stored in /usr/local/apache/htdocs. 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. To fix this we use the suPHP_GlobalDocRoot and suPHP_DontCheckVHostDocRoot directives that we applied the earlier patches for. 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>

In this example, you need to replace %user% with a user that does exist on the server. Typically, we have an account that we set up on each of our servers, which we can use for testing purposes for various tasks on the server. I usually use the username associated with this account here. I suppose you could just create a user on the server and use that information here. The fact is, a username and group (usually the group is the same as the user) needs to be defined here so that suPHP knows what user to execute the PHP scripts as.

If you have any VirtualHosts already set up on the server, then you need to specify a suPHP_UserGroup for them as well. Add the following to their VirtualHost container:

<IfModule mod_suphp.c>
suPHP_UserGroup %user% %user%
</IfModule>

Where %user% refers to the username associated with that specific account.

I also encourage you to disable any Apache PHP modules you may have enabled on your server. You really do not want to run suPHP and PHP as an Apache module at the same time. Find the lines:

LoadModule php4_module       libexec/libphp4.so
AddModule mod_php4.c

And comment them out. Or you may have php5 modules installed. In any case, you should probably disable them.

Now save the httpd.conf file and restart Apache.

/scripts/restartsrv_httpd

Now you can test this to see if suPHP is working correctly. Place a phpinfo.php file in the /usr/local/apache/htdocs directory.

/usr/local/apache/htdocs/phpinfo.php:
<?php phpinfo(); ?>

In order for this to work, you need to change the ownership of this file so that it is reflected correctly by what was defined in the httpd.conf file in the main IP VirtualHost section.

chown %user%:%user% /usr/local/apache/htdocs
chown %user%:%user% /usr/local/apache/htdocs/phpinfo.php

Now when you visit http://mainip/phpinfo.php or http://host.name.com/phpinfo.php you should see a phpinfo page. The Server API should say CGI and the Configure Command should be the configuration line you used when you compiled PHP.

Now when you create accounts on the server, the necessary suPHP_UserGroup will be added to that VirtualHost section because of the changes to the CPanel Apache VirtualHost template. So when you create a new account, it is using suPHP for PHP.

Now if a specific account needs a customized php.ini setting, you can define a special php.ini file for them. Typically, I will create a php directory under the account’s home directory and place a copy of the php.ini file in there.

cd /home/%user%
mkdir php
cd php
cp /usr/local/Zend/etc/php.ini ./

Now edit the php.ini file in /home/%user%/php and make the necessary changes. Then edit /etc/httpd/conf/httpd.conf and find that specific VirtualHost entry. In the <IfModule mod_suphp.c> container add:

suPHP_ConfigPath /home/%user%/php

Replacing %user% with the actual username of the account and the path to the directory that contains the php.ini file (Don’t point directly to the php.ini file).

In this particular example, the changes made to the php.ini file will apply to that entire VirtualHost. All PHP scripts executed within that VirtualHost will use the customized php.ini file when executing PHP code. This differs from the phpsuexec alternative which required separate php.ini files to be placed in each directory (the ability to use customized php.ini files in phpsuexec has since been disabled by CPanel).

You can further customize this by defining multiple php.ini files and using <Location> containers within VirtualHosts to be more specific about what php.ini file to read. For example, you might have something like:

<IfModule mod_suphp.c>

suPHP_UserGroup %user% %user%
suPHP_ConfigPath /home/%user%/php
<Location /store>
suPHP_ConfigPath /home/%user%/php/store
</Location>
</IfModule>

This uses a customized php.ini file stored in /home/%user%/php for all PHP script requests on this VirtualHost, except for request made at or below /store. In this case, the php.ini file at /home/%user%/php/store is used.

If you compiled PHP4 and PHP5 to run concurrently and if you have the setup I have described above where PHP4 is the main PHP and PHP5 is parsed through .php5 files, then if you have a user that wants to run PHP5 on all php file extensions, you can allow this by adding the following into that account’s VirtualHost inside the <IfModule mod_suphp.c> container:

AddHandler x-httpd-php5 .php .php3 .php4 .phtml

Now files with a .php, .php3, .php4, .phtml, and .php5 extension will be parsed as PHP5 for that specific VirtualHost.

This allows you to more seamlessly integrate PHP5 into your hosting offering, while continuing to run PHP4.

suPHP can be a wonderful tool and can allow a lot of customization to be done. Its not easy to get it to work with CPanel, but once you get an understanding of how it works and what changes to make, you can better integrate it into other servers.

If you have any questions or comments concerning this feel free to contact me and let me know. I won’t guarantee that I will have any answers, but I will give them if I have any.

Downloads

suPHP — suPHP website, developed by Sebastian Marsching

Application.patch — Contributed by Andrea suphp mailing list (October 24, 2005)
mod_suphp.patch — Contributed by Andrea suphp mailing list (October 24, 2005)
suphp-0.6.1-userdir.patch — Contributed by Miles Lubin suphp mailing list (December 2, 2005)
suphp-0.6.1-cpanel.patch — My Customized suphp cpanel patch
suphp.conf — Sample suphp.conf file
php-source.sh — php-source.sh script for PHP source contributed by J.P.G. Sleddens suphp mailing list (May 23, 2006)