Wednesday, February 3, 2010

Stock CentOS with SuPHP

SkyHi @ Wednesday, February 03, 2010
REMEMBER Always make backups!



Why Use SuPHP?

I use SuPHP due to the fact that I work for a web hosting provider, and I seek out new ways to accomplish tasks. One such task, is making PHP run under a different user account than that of the web servers own. For years, SuEXEC has been used, and rather haphazardly by adding variables into the /proc file system each time the server reboots. SuEXEC requires PHP scripts to be chmod 755, SuPHP I can require anything, or the standard chmod 644, which more people coming from other hosting providers will be used to.

One thing that I have found true, is that the less configuration and setup a customer has to do to get their website to work on your service, they happier they will be, and the less they bother your support staff. Being a member of the support staff, specifically the System Administration team, it affects me.

Here, I provide my own personal HOWTO, on getting SuPHP setup on a stock CentOS/RHEL 5.x server. By "stock" I mean everything is installed via RPM, either with a utility like "yum" or "up2date", or simply by hand with 'rpm -ivh '.

Necessary RPM's

The following PHP related RPM's were installed on my system. By default, I want PHP w/ MySQL support, developer libraries, PDO support, and multi-language support (mbstring).
php php-devel php-common php-cli php-mysql php-mbstring php-pdo
The following non-PHP related RPM's were installed. Standard Apache web server, with the developer package to provide the APXS utilities & headers. MySQL server is also installed, however if your webserver is not a database server, and either you will have a separate database server, or none at all, you can be safe removing the 'mysql-server' package. The others provide the MySQL client for use with PHP and/or other applications. Also added, is mod_ssl for SSL enabled webpages, and mod_suphp (bingo!). mod_auth_mysql & perl-DBD-MySQL have been used for PHP/MySQL & Perl/CGI (resp.) database authentication mechanisms commonly used with more modern shopping carts, NATS systems, and website member authentication.
httpd httpd-devel mysql mysql-server mysql-devel
mod_ssl mod_suphp mod_auth_mysql perl-DBD-MySQL
In my case, I replaced the stock CentOS RPM's for MySQL with the one's from This is a personal & biased opinion, but I feel that MySQL binaries are better compiled since they know their own software the best. However, the same argument can be said of Linux OS Developers, that they know their OS' the best, and can compile MySQL to suit. Whichever you chose, should work just fine. Again, if this isn't going to be a MySQL database and webserver, then you can safely not install the MySQL-server* package. The MySQL-shared-compat* package includes headers for programs that may rely on older MySQL versions, such as 3.23.x, 4.x and MySQL 5.0, and are installed due to CentOS/RHEL utilizing MySQL 4.1 & 5.0.

Optional RPM's

I consider these to be mandatory on a modern web server for the mere fact, that nearly all web developers utilize third party web applications that make use of them. Graphics utilities like GD and ImageMagick are used by most forum & bulletin board applications, and even security software such as CAPTCHA's may use GD and/or ImageMagick. Other additions include mod_python & mod_perl for those web developers that want cutting edge scripting abilities. With "cutting edge" in mind, I also have a habit of including the following (and all their dependencies):
mod_perl mod_python
php-gd php-xml php-mhash php-mcrypt php-ncurses php-bcmath php-imap php-pear
php-tidy libtidy php-pear-Date php-pear-DB php-pear-File php-pear-Mail 
php-pear-Mail-Mime php-pear-Net-SMTP php-pear-Net-URL php-pear-Net-Socket
gd gd-devel gd-progs ImageMagick ImageMagick-devel ImageMagick-perl

Editing Apache and suPHP Configs

  • First, I want to stop the loading of mod_php, or the PHP Apache module, if they currently exist. This is so it does not load on startup. To do this, rename the php module config file:
mv /etc/httpd/conf.d/php.conf /etc/httpd/conf.d/php.conf.orig2007

  • Edit /etc/httpd/conf.d/suphp.conf, and change the following:
  suPHP_Engine off
  suPHP_Engine on

-- Remove the comment from the following:
  #suPHP_ConfigPath /etc
  suPHP_ConfigPath /etc

-- Remove the comment from the following:
  # suPHP_AddHandler x-httpd-php
  suPHP_AddHandler x-httpd-php
  • Edit /etc/suphp.conf, and change the following:



  • Next, edit /etc/httpd/conf/httpd.conf file. In this example, we'll comment out a few global defaults, and make a few minor changes:
Change (For security reasons):
  ServerTokens OS
  ServerTokens Prod

Change to your liking:
  StartServers       8
  MinSpareServers    5
  MaxSpareServers   20
  ServerLimit      256
  MaxClients       256
  MaxRequestsPerChild  4000
  StartServers      10
  MinSpareServers   10
  MaxSpareServers   25
  ServerLimit     1024
  MaxClients      1024
  MaxRequestsPerChild  10000

Change (if uncommented):

  DirectoryIndex index.html index.html.var
  DirectoryIndex index.php index.html index.htm index.html.var

  LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
To: (comment it out)
  #LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

  LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
To: (comment out example, copy and change end from "combinedio" to "combined")
  #LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
  LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combined

  ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
To: (comment out global scope)
  #ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"

    AllowOverride None
    Options None
    Order allow,deny
    Allow from all
To: (comment out)
  #    AllowOverride None
  #    Options None
  #    Order allow,deny
  #    Allow from all
Now add NameVirtualHost & VirtualHost directives. Note that I have included "suPHP_UserGroup userid groupid", required for suPHP to work properly AND I've also enabled SuEXEC for CGI scripts, though you CAN set SuPHP to handle both. The old-fashioned SuEXEC fanatic still wants CGI to be put through a tried & true SuEXEC system. Example:

    ServerAdmin webmaster@int.domain
    ServerAlias *

    SuexecUserGroup userid groupid
    suPHP_UserGroup userid groupid
    ErrorLog logs/
    CustomLog logs/ combined

    DocumentRoot /var/www/virtual/default_vhost/htdocs
       Options -Indexes SymLinksifOwnerMatch
       AllowOverride Options FileInfo AuthConfig Limit

    ScriptAlias /cgi-bin/ "/var/www/virtual/default_vhost/cgi-bin/"
       AllowOverride None
       Options SymLinksifOwnerMatch 
       Order allow,deny
       Allow from all

    # Personal addition to disable TRACE method in Apache
       RewriteEngine On
       RewriteCond %{REQUEST_METHOD} ^TRACE
       RewriteRule .* - [F]

Editing /etc/php.ini

Edit, to your liking, the /etc/php.ini file. I usually like to make sure global_variables is "OFF", as most web applications these days, should work without it. Also, unless you restrict your users heavily, you can usually have your user add an option to the necessary folder using an .htaccess file. If performance is an issue, it can also be enabled per VirtualHost in Apache's config file.
Change the following under [sessions], from:
;session.save_path = "/var/lib/php/session"
session.save_path = "/tmp"

Finishing Up

You should be ready to go, simply start apache using "service httpd start" and away you go. Your PHP scripts should run as the user instead of the web server user.