How to: PHP 5 CLI to PHP 5 CGI + suPHP

yahooyoga

New member
Joined
Aug 13, 2021
Messages
1
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
 
Back
Top