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)
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
cd /usr/local/directadmin/custombuild ./build update ./build clean nano options.conf
and change
php5_cli=yes php5_cgi=no
to
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:
./build used_configs
Now we can build PHP
./build php
Ensure the new php.ini is correct.. the old one was located at /usr/local/lib/php.ini
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
./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)
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
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
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
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
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)
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:
#!/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)
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:
#!/bin/sh chattr -i /usr/local/directadmin/data/users/$username/php/ exit 0;
create php.ini files for current users
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
cp /usr/local/directadmin/data/templates/virtual_host2* /usr/local/directadmin/data/templates/custom/
change VirtualHost containers to look for php.ini override
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
|*if SUPHP="1"| SetEnv PHP_INI_SCAN_DIR /usr/local/directadmin/data/users/|USER|/php/ |*endif|
rewrite httpd configs for current users
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.
nano /usr/local/etc/php5/cgi/php.ini
find the open_basedir line and change to:
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:
nano /etc/httpd/conf/httpd.conf
find the <IfModule mod_suphp.c> section within the <Directory “/var/www/html”> block and change to:
<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.
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:
/usr/local/bin/php -c /usr/local/directadmin/data/users/accountname/php/php.ini /home/accountname/domains/domainname/public_html/filetocron.php