[HOWTO] mpm-itk

hansmiddelhoek

Verified User
Joined
Apr 26, 2005
Messages
40
Location
Netherlands
A couple of month's ago I started testing with mpm-itk. That's a module for Apache to run http requests as a user. Like suPHP does for PHP, that will make PHP scripts run as the user instead of the apache default user (apache, nobody, www). There are several alternatives to suPHP like mod_ruid2, mpm-peruser, mpm-itk and possibly some others. We didn't like to use suPHP for several reasons, but mostly because of the speed affects. In another topic I mentioned other things about suPHP and discussed the implementation of mpm-itk with zEitEr (Alex) who helped me alot by getting mpm-itk working as it should be. So, Thanks for your help Alex! http://www.directadmin.com/forum/showthread.php?t=40919

Our servers are running FreeBSD, so this howto is written on base of that. I assume it will work on Linux servers as well, there are no special FreeBSD thing's in the setup, at most a little command syntax difference. Alex tried mpm-itk on CentOS a few years ago and that didn't work, so possibly you experience the same on Linux distro's, I can't tell anything about it, because we run DirectAdmin only on FreeBSD. Just try and tell me if it works :)

In a nutshell what needs to be done.
Code:
1) Manually patch apache source and re-tar
2) Put NEW md5sum in versions.txt, replace the old one
3) Make sure autover=no in options.conf
4) Edit configure.apache and add "--with-mpm=itk"
5) Rebuild apache
6) Modify DirectAdmin's Apache virtual host templates
7) Make sure that certain options are set in your exim.conf
8) Reset user permissions in every user home account and /var/www/html

1)
Code:
cd /root; mkdir apache_patches; cd apache_patches
wget http://mpm-itk.sesse.net/apache2.2-mpm-itk-2.2.17-01.patch
This patch is created for Apache 2.2.17, there's a slight change in newer versions. If you're applying the patch on Apache 2.2.19 or higher, execute following command:
Code:
perl -pi -e 's/beos\|event\|worker\|prefork\|mpmt_os2/beos\|event\|worker\|prefork\|mpmt_os2\|winnt/' apache2.2-mpm-itk-2.2.17-01.patch
Code:
cd /usr/local/directadmin/custombuild; tar xzf httpd-2.2.21.tar.gz; cd httpd-2.2.21
patch -p1 < /root/apache_patches/apache2.2-mpm-itk-2.2.17-01.patch
# Check if the output of following command shows 0, if not, there are errors that need to be solved first.
Code:
echo $?
Don't follow below steps if the output of above command wasn't 0.
Code:
autoconf
cd /usr/local/directadmin/custombuild; mv httpd-2.2.21.tar.gz httpd-2.2.21.tar.gz.ORIG; tar czf httpd-2.2.21.tar.gz httpd-2.2.21
md5 -q httpd-2.2.21.tar.gz (on Linux: md5sum httpd-2.2.21.tar.gz)

2) Edit versions.txt (ee, nano, vi)
replace md5 sum after apache2.2 and save file

3) Make sure autover=no in options.conf
Code:
grep -i 'autover=no' /usr/local/directadmin/custombuild/options.conf
Edit options.conf if autover isn't set to no.

4) Edit configure.apache and add "--with-mpm=itk"
Code:
cd /usr/local/directadmin/custombuild/custom/ap2
Edit (ee, nano, vi) configure.apache
add "--with-mpm=itk", mind the \ at the end of lines, except for last line of file
# Save configure.apache

5) Rebuild apache
Code:
cd /usr/local/directadmin/custombuild; ./build apache

Your Apache installation has mpm-itk integrated.

6) Modify DirectAdmin's Apache virtual host templates
This will copy the virtual host templates to the custom templates directory, if you already have custom virtual host templates, do not copy, but directly edit them.
Code:
cd /usr/local/directadmin/data/templates
cp virtual_host2*.conf custom
cd custom
Edit virtual_host2*.conf files (ee virtual_host2*.conf) All template files need to be edited the same way.

Change:
Code:
SuexecUserGroup |USER| |GROUP|
In:
Code:
<IfModule !mpm_itk_module>
	SuexecUserGroup |USER| |GROUP|
</IfModule>
Add following at the end of each file right before </virtualhost>:
Code:
<IfModule mpm_itk_module>
	AssignUserId |USER| |GROUP|
</IfModule>

Add following lines to /etc/httpd/conf/extra/httpd-includes.conf
Code:
<Directory "/var/www/html">
    Options -Indexes FollowSymLinks
    AllowOverride All
    Order allow,deny
    Allow from all
   <IfModule mpm_itk_module>
        AssignUserId webapps webapps
   </IfModule>
   <IfModule mod_suphp.c>
        suPHP_Engine On
        suPHP_UserGroup webapps webapps
	SetEnv PHP_INI_SCAN_DIR
   </IfModule>
</Directory>

7) Make sure that certain options are set in your exim.conf
Your exim.conf (/etc/exim.conf) needs to have following options:
Code:
local_from_check = false
untrusted_set_sender = *
These options need to be set (without #), restart exim if you changed anything. This is needed to get the right Return-Path header in emails send from Apache. Without these settings the Return-Path will be set like:
<user>@<hostname> ([email protected])

8) Reset user permissions in every user home account and /var/www/html
Make a new file, eg. /root/resetperm.sh with the following content:
Code:
#!/bin/sh

SAG=`grep -c "secure_access_group=" /usr/local/directadmin/conf/directadmin.conf`
APH=`grep -c "apache_public_html=1" /usr/local/directadmin/conf/directadmin.conf`
if [ $SAG -eq 1 ] && [ $APH -eq 0 ]; then
	echo "secure_access_group is set in /usr/local/directadmin/conf/directadmin.conf"
	echo "apache_public_html is disabled on this server"
	echo "This is good, and all permissions will be set correctly."
	sleep 8
else
	echo "secure_access_group is not set in /usr/local/directadmin/conf/directadmin.conf or"
	echo "apache_public_html is enabled on this server."
	echo "This isn't the best security approach, we recommend to set this in your directadmin.conf:"
	echo "secure_access_group=access"
	echo "apache_public_html=0 (or remove it from the file)"
	echo "You can continue running this script if you like, this permission settings will be skipped, but"
	echo "we strongly recommend setting above first, and than run this script. That wil correct all permissions"
	echo "on your system automatically."
	echo "Please read instructions on DirectAdmin knowledgebase: http://www.directadmin.com/features.php?id=961"
	echo
	echo -n "Do you really want to continue? [y/n]: "
	read CONTINUE
	if [ "$CONTINUE" = "n" ] || [ "$CONTINUE" = "N" ] || [ "$CONTINUE" = "" ]; then
		echo "Exiting..."
		echo "Please set above settings and rerun this script, this question won't be asked again if set correctly."
		exit 1;
	fi
fi

echo "This script can take some time to complete, please don't interrupt!"
sleep 5

for USER in `ls -1 /usr/local/directadmin/data/users`; do
	if [ $SAG -eq 1 ] && [ $APH -eq 0 ]; then
		# Get user type
		USERTYPE=`grep "usertype" /usr/local/directadmin/data/users/${USER}/user.conf | cut -d= -f2`

		# Correct permissions of user home directory
		if [ "$USERTYPE" = "user" ]; then
			chmod 711 /home/${USER}/domains
			chown ${USER}:${USER} /home/${USER}/domains
			chmod 711 /home/${USER}/domains/*
			chown ${USER}:${USER} /home/$USER/domains/*
			find /home/${USER}/domains/* -type d -depth 1 -name "p*_html" -exec chmod 755 {} \; -exec chown ${USER}:${USER} {} \;
		else
			# Usertype is admin or reseller
			find /home/${USER}/domains -type d -depth 1 ! -name "default" ! -name "sharedip" ! -name "suspended" -exec chmod 711 {} \; -exec chown ${USER}:${USER} {} \;
			find /home/${USER}/domains/* -type d -depth 1 -name "*_html" -exec chmod 755 {} \; -exec chown ${USER}:${USER} {} \;
		fi
	fi

	# Set all user data to $USER:$USER
	chown -R ${USER}:${USER} /home/${USER}/domains/*/*_html/*
	chown -R ${USER}:${USER} /home/${USER}/domains/*/*_html/.*

	# Find all directories with at least 755 but not 755
	# Don't touch 000 chmodded direcotries or other stricter settings than 755
	find /home/$USER/domains/*/*_html/* -type d -perm -755 ! -perm 755 -print0 | xargs -0 chmod 755

	# Find all files with at least 644 but not 644
	# Don't touch 000 chmodded files or other stricter settings than 644
	find /home/$USER/domains/*/*_html/* -type f -perm -644 ! -perm 644 -print0 | xargs -0 chmod 644
	echo -n "."
done

echo
echo "Resetting file and directory permissions finished."

if [ $SAG -eq 1 ] && [ $APH -eq 0 ]; then
	echo "action=rewrite&value=secure_access_group" >> /usr/local/directadmin/data/task.queue
fi
echo "action=rewrite&value=httpd" >> /usr/local/directadmin/data/task.queue
echo "action=httpd&value=restart" >> /usr/local/directadmin/data/task.queue
echo "Please wait some minutes while DirectAdmin task queue will execute and restart all services."
Chmod your file 700 and execute it. This will reset file and directory permissions in all user home directories and advises you to use secure_access_group (http://www.directadmin.com/features.php?id=961) and disable apache_public_html. These settings can be found in directadmin.conf but will be checked by the script. This script won't change these settings automatically but tells you if you should. At the end of the script, when permissions are set, secure_access_group permissions are reset, the virtual host templates are rewritten, and Apache will be restarted, all done by DirectAdmin's dataskq (task.queue).
Code:
chmod 700 /root/resetperm.sh
# Execute the script:
/root/resetperm.sh
Possibly you'll get some errors like these, but that's no problem, this is because of admin/reseller users that don't own a domain (in reseller level).
Code:
chown: /home/admin/domains/*/*_html/*: No such file or directory
chown: /home/admin/domains/*/*_html/.*: No such file or directory
find: /home/admin/domains/*/*_html/*: No such file or directory
find: /home/admin/domains/*/*_html/*: No such file or directory

Set correct permissions /var/www/html (roundcube/squirrelmail/phpmyadmin/etc)
Code:
chown -R webapps:webapps /var/www/html

Wait for dataskq to complete (runs every minute). Before all processes are finished it can take up to a few minutes. Apache will be restarted several times, please wait long enough (5 minutes or longer) before assuming it didn't work.

Check if Apache is restarted correctly:
Code:
apachectl status

Repeat following command till you get output:
You'll see httpd requests running as a user, and/or webapps (roundcube, squirrelmail, phpmyadmin, etc)
user apache shouldn't be used anymore, if all went fine
Code:
ps wwwuax | grep httpd | grep -v root

You're done!

If you own more than one server, you can build Apache once (step 1) and upload it to each server. This will save you 5-10 minutes for each server.

We're running mpm-itk on all our servers. A few servers for 2 month's already, others a month or a few weeks. We haven't had any issues with these procedure and no complaining customers. It really works great! The load impact is below 5% in our setups.

If you have any questions, just ask.

Sources:
http://www.directadmin.com/forum/showthread.php?t=40919
http://mpm-itk.sesse.net/
http://blog.stuartherbert.com/php/2008/04/19/using-mpm-itk-to-secure-a-shared-server/

Kind Regards,
Hans Middelhoek
 
After a few month's we use mpm-itk, we came across a very little problem. If you access your site by http://srv1.domainname.com/~user1 the userid isn't set and the process still runs as user 'apache'. Quite obvious off course, because the virtual host of the domainname won't match.

Thinking and searching for a solution I can only think of specifying <Directory> directives in the virtual host template, but above the opening of <Virtualhost>.

Like this:
Code:
<Directory /home/|USER|>
        <IfModule mpm_itk_module>
                AssignUserId |USER| |GROUP|
        </IfModule>
</Directory>

<VirtualHost |IP|:80 |MULTI_IP|>
...

This means that the directory is specified before and within the virtualhost, do you think that could cause problems anywhere? I've tested this and it works like expected, as far as I can see. If you see any possible problems I would like to hear it.

Thanks in advance.
 
I investigated and tested this further. I'm convinced that this is the right approach.
Directory directives in Apache are followed in a specific order, not by occurrence in the configuration.
Code:
<Directory /home/user123>
        <IfModule mpm_itk_module>
                AssignUserId |USER| |GROUP|
        </IfModule>
</Directory>
Matches first, and then:
Code:
<Directory /home/user123/subdir>
or
Code:
<Directory /home/user123/domains/user123domain.com/public_html>

All setting are inherited but can be overruled by setting another value. For example setting 'Deny from all' in /home/user123 and 'Allow from all' in /home/user123/domains/user123domain.com/public_html.

We implemented this on our servers and it solves our issue.
 
Thanks for this nice How-to. We've just switched from mod_fcgid to itk_mpm + mod_php since mod_fcgid didn't handle limits per vhost very well.

But I've found one problem on our Debian boxes running Squeeze. After php compilation we run into some apache segfaults. This was caused by ionCube loader which was included in php.ini. The only solution that we found was to not loaded it site-wide but to allow the clients to load it with dl() function.

Unfortunately due to the fact that apache uses itk_mpm instead of prefork PHP will be compiled with thread-safety enabled (ZTS) and dl() function is disabled in thread-safe PHP.

The only workaround for us was to change php package to compile without ZTS for itk_mpm.

Here's the fix for everyone who wants PHP with Thread Safety disabled + itk_mpm:
Code:
cd /usr/local/directadmin/custombuild
tar zxf php-5.2.17.tar.gz
cd php-5.2.17
Edit "configure" file and change two appearances of:
Code:
if test "$APXS_MPM" != "prefork"; then
to
Code:
if test "$APXS_MPM" != "itk" -a "$APXS_MPM" != "prefork"; then

Now run following commands:

Code:
cd ..
mv php-5.2.17.tar.gz php-5.2.17.tar.gz.ORIG
tar -c php-5.2.17 | gzip -5 > php-5.2.17.tar.gz
md5sum php-5.2.17.tar.gz

And put new MD5 for php-5.2.17 in versions.txt.

In the end run:
Code:
./build php n

That's it. You have PHP with disabled ZTS and dl() works as expected.
 
Last edited:
This is a great thread; thanks guys. I would love to implement this on my servers, but I am hesitant to do so due to the number of modifications to go through. :)
 
worked perfectly for me with apache 2.2.22, thanks a lot. but setting permissions cause a temporary write errors on sites. it would be better to wait until mpm start working.
 
Back
Top