HOWTO: PHP 5 CLI to PHP 5 CGI + suPHP Directadmin

Orjinal Link: http://www.directadmin.com/forum/showthread.php?t=29483&highlight=howto+cgi
HOWTO: PHP 5 CLI to PHP 5 CGI + suPHP

I recently decided to switch from using PHP CLI to CGI mode with suPHP. Here are the steps I followed to ensure everything was working. Let me know if you spot any flaws or know of a better way of doing this.

NOTE: I am continually updating this post. It is safe to assume that all posts which mention improvements/security fixes have been included where relevant if they were posted before the last time this post was edited. (See bottom of this post for timestamp)

Ok, lets get started..

suPHP doesn’t allow the use of php_flag and php_value in .htaccess files, so find users with these setup and deal with them (or their sites will throw a 500 error)

Code:
find /home/*/domains/*/public_html -name ".htaccess" | xargs grep "php_"

Once you have dealt with those sites, suPHP should be good to go..

Edit the custombuild options file to use PHP in CGI mode

Code:
cd /usr/local/directadmin/custombuild
./build update
./build clean
nano options.conf

and change

Code:
php5_cli=yes
php5_cgi=no

to

Code:
php5_cli=no
php5_cgi=yes

If you need a custom config of PHP or suPHP then you can find which config files to change using:

Code:
./build used_configs

Now we can build PHP

Code:
./build php

Ensure the new php.ini is correct.. the old one was located at /usr/local/lib/php.ini

Code:
nano /usr/local/etc/php5/cgi/php.ini

It might be worth using custombuild to secure php some more. Using secure_php disables register_globals and adds some potentially vulnerable functions to the disable_functions list in the main php.ini file. These can be overridden on an individual basis per user if need be in their individual php.ini files

Code:
./build secure_php

We need to reset ownership of files as suPHP won’t allow access to ones owned by apache (they way the CLI version of PHP works)

Code:
ls -l /home | grep '^d' | awk '{system("chown -R " $3 ":" $4 " /home/" $9 "/domains")}'

Sessions will also have wrong ownership or now be corrupt so remove those

Code:
rm -f /tmp/sess_*

Sites which have files or directories with global write access will also cause suPHP to throw an error, therefore change all files to 644 and directories to 755

Code:
find /home/*/domains/*/public_html -type f -exec chmod 0644 {} \; -print
find /home/*/domains/*/private_html -type f -exec chmod 0644 {} \; -print
find /home/*/domains/*/public_html -type d -exec chmod 0755 {} \; -print
find /home/*/domains/*/private_html -type d -exec chmod 0755 {} \; -print

perl and cgi scripts need execute permissions though

Code:
find /home/*/domains/*/public_html -name "*.pl" -exec chmod 0744 {} \; -print
find /home/*/domains/*/private_html -name "*.pl" -exec chmod 0744 {} \; -print
find /home/*/domains/*/public_html -name "*.cgi" -exec chmod 0744 {} \; -print
find /home/*/domains/*/private_html -name "*.cgi" -exec chmod 0744 {} \; -print

Make sure webmail and phpMyAdmin work by resetting their ownership and permissions also

Code:
chown -R webapps:webapps /var/www/html
find /var/www/html -type f -exec chmod 0644 {} \; -print
find /var/www/html -type d -exec chmod 0755 {} \; -print
find /var/www/html -name "*.pl" -exec chmod 0744 {} \; -print
find /var/www/html -name "*.cgi" -exec chmod 0744 {} \; -print

Now lets enable open_basedir per user, and create user’s own tmp directories to make the server more secure. (I realize that I have done this on a per user basis rather than per domain, it should be straight forward to change if you do want it per domain)

automate creation of per user php.ini for new users (make sure the chown refers to your DirectAdmin user)

Code:
touch /usr/local/directadmin/scripts/custom/user_create_post.sh
chmod 755 /usr/local/directadmin/scripts/custom/user_create_post.sh
chown diradmin:diradmin /usr/local/directadmin/scripts/custom/user_create_post.sh
nano /usr/local/directadmin/scripts/custom/user_create_post.sh

use the following shell script:

Code:
#!/bin/sh

mkdir /usr/local/directadmin/data/users/$username/php/
chown $username:$username /usr/local/directadmin/data/users/$username/php/
touch /usr/local/directadmin/data/users/$username/php/php.ini
echo "open_basedir = /home/$username/:/tmp/" >> /usr/local/directadmin/data/users/$username/php/php.ini
chown root:root /usr/local/directadmin/data/users/$username/php/php.ini
chattr +i /usr/local/directadmin/data/users/$username/php/

exit 0;

note that in the above script you may need to alter the open_basedir setting to add allowed paths (e.g. PHP’s pear modules /usr/local/php5/lib/php) depending on your server setup

in order to remove the user completely we need to release the chattr +i on the php.ini config directory first (make sure the chown refers to your DirectAdmin user)

Code:
touch /usr/local/directadmin/scripts/custom/user_destroy_pre.sh
chmod 755 /usr/local/directadmin/scripts/custom/user_destroy_pre.sh
chown diradmin:diradmin /usr/local/directadmin/scripts/custom/user_destroy_pre.sh
nano /usr/local/directadmin/scripts/custom/user_destroy_pre.sh

use the following shell script:

Code:
#!/bin/sh

chattr -i /usr/local/directadmin/data/users/$username/php/

exit 0;

create php.ini files for current users

Code:
ls -l /home | grep '^d' | awk '{system("username="$3" /usr/local/directadmin/scripts/custom/user_create_post.sh")}'

copy VirtualHost templates to custom directory so they are not overwritten when DirectAdmin updates

Code:
cp /usr/local/directadmin/data/templates/virtual_host2* /usr/local/directadmin/data/templates/custom/

change VirtualHost containers to look for php.ini override

Code:
nano /usr/local/directadmin/data/templates/custom/virtual_host2.conf
nano /usr/local/directadmin/data/templates/custom/virtual_host2_sub.conf
nano /usr/local/directadmin/data/templates/custom/virtual_host2_secure.conf
nano /usr/local/directadmin/data/templates/custom/virtual_host2_secure_sub.conf

add this after the ErrorLog

Code:
|*if SUPHP="1"|
        SetEnv PHP_INI_SCAN_DIR /usr/local/directadmin/data/users/|USER|/php/
|*endif|

rewrite httpd configs for current users

Code:
echo "action=rewrite&value=httpd" >> /usr/local/directadmin/data/task.queue

To make sure webmail and phpMyAdmin work, set open_basedir in the global php.ini which will apply to webapps.

Code:
nano /usr/local/etc/php5/cgi/php.ini

find the open_basedir line and change to:

Code:
open_basedir = /var/www/html/:/tmp/

Then change the httpd.conf file to make sure the php.ini file isn’t overridden by user’s specific php.ini files:

Code:
nano /etc/httpd/conf/httpd.conf

find the <IfModule mod_suphp.c> section within the <Directory “/var/www/html”> block and change to:

Code:
   <IfModule mod_suphp.c>
        suPHP_Engine On
        suPHP_UserGroup webapps webapps
        SetEnv PHP_INI_SCAN_DIR
   </IfModule>

That should be the lot, make sure Apache is restarted.

Code:
service httpd restart

Hopefully everything is working!

Notes
—–

If a customer wants to use cronjobs they need to add the php.ini in the cron command:

Code:
/usr/local/bin/php -c /usr/local/directadmin/data/users/accountname/php/php.ini /home/accountname/domains/domainname/public_html/filetocron.php