Running Vhosts Under Separate UIDs/GIDs With Apache2 mpm-peruser On Debian Etch

Version 1.0
Author: Falko Timme

This article explains how you can install and configure apache2-mpm-peruser on a Debian Etch server. apache2-mpm-peruser is an MPM (Multi-Processing Module) for the Apache 2 web server, very similar to apache2-mpm-itk, but faster (almost as fast as apache2-mpm-prefork). mpm-peruser allows you to run each of your vhosts under a separate UID and GID - in short, the scripts and configuration files for one vhost no longer have to be readable for all the other vhosts. It is based on metuxmpm, a working implementation of the perchild MPM. The result is a sane and secure web server environment for your users, without kludges like PHP's safe_mode.

This document comes without warranty of any kind! I do not issue any guarantee that this will work for you!

 

1 Preliminary Note

For speed considerations, take a look at http://blog.stuartherbert.com/php/2008/03/20/using-mpm-peruser-to-secure-a-shared-server/.

I'm assuming you have a working Apache2 installation with mod_php on your Debian Etch server, e.g. installed like this:

apt-get install apache2-mpm-prefork libapache2-mod-php5

When you create a PHP file with the phpinfo(); function, e.g. like this...

vi /var/www/info.php
<?php
phpinfo();
?>

... and call it in a browser, you'll see that prefork is listed in the Loaded Modules row under apache2handler:

 

2 Installing apache2-mpm-peruser

Unlike apache2-mpm-itk, apache2-mpm-peruser is not available as a Debian package, therefore I will build my own Debian package (I will use the apache2-mpm-itk source package as the basis for building my apache2-mpm-peruser Debian package since they are so similar).

Before I start building the package, I install a few prerequisites:

apt-get install build-essential dpkg-dev fakeroot debhelper dpatch apache2-prefork-dev libcap-dev apache2-src autoconf

Then I go to /usr/src and download the apache2-mpm-itk source package:

cd /usr/src
apt-get source apache2-mpm-itk
ls -l
server1:/usr/src# ls -l
total 52
drwxr-xr-x 3 root root  4096 2008-08-16 13:29 apache2-mpm-itk-2.2.3-01
-rw-r--r-- 1 root src  11392 2007-10-03 19:02 apache2-mpm-itk_2.2.3-01-2.diff.gz
-rw-r--r-- 1 root src    664 2007-10-03 19:02 apache2-mpm-itk_2.2.3-01-2.dsc
-rw-r--r-- 1 root src  29071 2006-10-31 00:04 apache2-mpm-itk_2.2.3-01.orig.tar.gz
server1:/usr/src#

Next I rename the apache2-mpm-itk directory to apache2-mpm-peruser:

mv apache2-mpm-itk-2.2.3-01 apache2-mpm-peruser-2.2.3-01

Then I go to that directory, download the mpm-peruser patch and delete the mpm-itk patch that's already in the directory:

cd apache2-mpm-peruser-2.2.3-01/
wget http://www.telana.com/files/httpd-2.2.3-peruser-0.3.0.patch
rm -f apache2.2-mpm-itk.patch

Now let's go to the debian/ subdirectory:

cd debian/
ls -l
server1:/usr/src/apache2-mpm-peruser-2.2.3-01/debian# ls -l
total 64
-rw-r--r-- 1 root root    10 2008-08-15 16:21 apache2-mpm-itk.dirs
-rw-r--r-- 1 root root   633 2008-08-15 16:21 apache2-mpm-itk.postinst
-rw-r--r-- 1 root root   561 2008-08-15 16:21 apache2-mpm-itk.preinst
-rw-r--r-- 1 root root   342 2008-08-15 16:21 apache2-mpm-itk.prerm
-rw-r--r-- 1 root root   438 2008-08-15 16:21 changelog
-rw-r--r-- 1 root root     2 2008-08-15 16:21 compat
-rw-r--r-- 1 root root   980 2008-08-15 16:21 control
-rw-r--r-- 1 root root 31777 2008-08-15 16:21 copyright
-rwxr-xr-x 1 root root  1328 2008-08-15 16:21 rules
server1:/usr/src/apache2-mpm-peruser-2.2.3-01/debian#

We rename all files that contain itk in the file name:

mv apache2-mpm-itk.dirs apache2-mpm-peruser.dirs
mv apache2-mpm-itk.postinst apache2-mpm-peruser.postinst
mv apache2-mpm-itk.preinst apache2-mpm-peruser.preinst
mv apache2-mpm-itk.prerm apache2-mpm-peruser.prerm

Next we must modify the changelog file, e.g. like this:

cat /dev/null > changelog
vi changelog
apache2-mpm-peruser (2.2.3-01-1) stable; urgency=low

  * Initial port to Apache 2.2.

 -- Falko Timme <[email protected]>  Fri, 15 Aug 2008 14:29:36 +0100

Make sure that the last line has exactly one space at the beginning (before --) and two spaces between the email address and the date!

Now we open the control file and replace all occurrences of apache2-mpm-itk with apache2-mpm-peruser. I leave the Description as is, but replace ITK with Peruser. In the Conflicts line, I add apache2-mpm-itk:

vi control
Source: apache2-mpm-peruser
Section: net
Priority: extra
Build-Depends: apache2-src, apache2-prefork-dev, libcap-dev, autoconf, debhelper (>> 5.0.0)
Maintainer: Falko Timme <[email protected]>
Standards-Version: 3.7.2

Package: apache2-mpm-peruser
Provides: apache2-modules, apache2, httpd, httpd-cgi
Conflicts: apache2-mpm-prefork, apache2-mpm-itk, apache2-mpm-worker, apache2-mpm-perchild, apache2-mpm-event, apache2-common
Depends: ${apache:Depends}, ${shlibs:Depends}
Architecture: any
Description: multiuser MPM for Apache 2.2
 The Peruser Multi-Processing Module (MPM) works in about the same way as the
 classical "prefork" module (that is, without threads), except that it allows
 you to constrain each individual vhost to a particular system user. This
 allows you to run several different web sites on a single server without
 worrying that they will be able to read each others' files.
 .
 Please note that this MPM is highly experimental, and is not from the same
 tree as the other MPMs.

Next we modify the rules file:

vi rules

Replace

cd apache2.2/ && patch -p1 < ../apache2.2-mpm-itk.patch

with

cd apache2.2/ && patch -p1 < ../httpd-2.2.3-peruser-0.3.0.patch

Replace

sed 's,prefork,itk,;s,^".*/configure",../apache2.2/configure,;s,^"--srcdir=.*",--srcdir=../apache2.2/,' < /usr/share/apache2/build/config.nice > build-tree/config.nice

with

sed 's,prefork,peruser,;s,^".*/configure",../apache2.2/configure,;s,^"--srcdir=.*",--srcdir=../apache2.2/,' < /usr/share/apache2/build/config.nice > build-tree/config.nice

Replace

install -m 0755 build-tree/apache2 debian/apache2-mpm-itk/usr/sbin/

with

install -m 0755 build-tree/apache2 debian/apache2-mpm-peruser/usr/sbin/

Replace

echo "apache:Depends=apache2.2-common (= `dpkg -s apache2.2-common | grep ^Version: | cut -d" " -f2`)" >> debian/apache2-mpm-itk.substvars

with

echo "apache:Depends=apache2.2-common (= `dpkg -s apache2.2-common | grep ^Version: | cut -d" " -f2`)" >> debian/apache2-mpm-peruser.substvars

The complete file looks as follows:

#! /usr/bin/make -f

clean:
        dh_testdir
        dh_testroot
        dh_clean
        $(RM) -r build-tree/
        $(RM) -r apache2.2/
        $(RM) build-stamp

build: build-stamp
build-arch: build-stamp
build-stamp:
        dh_testdir
        mkdir build-tree/
        mkdir apache2.2/
        cd apache2.2/ && tar zxf /usr/src/apache2.tar.gz

        # workaround for apache2-src 2.2.3-3
        if [ -d apache2.2/apache2 ]; then \
                mv apache2.2/apache2/* apache2.2/; \
                rmdir apache2.2/apache2/; \
        fi

        cd apache2.2/ && patch -p1 < ../httpd-2.2.3-peruser-0.3.0.patch
        cd apache2.2/ && autoconf
        sed 's,prefork,peruser,;s,^".*/configure",../apache2.2/configure,;s,^"--srcdir=.*",--srcdir=../apache2.2/,' < /usr/share/apache2/build/config.nice > build-tree/config.nice
        chmod +x build-tree/config.nice
        cd build-tree/ && ./config.nice
        cd build-tree/ && $(MAKE)
        touch build-stamp

binary: binary-arch
binary-indep:
binary-arch: build-arch
        dh_testdir
        dh_testroot
        dh_installdirs

        install -m 0755 build-tree/apache2 debian/apache2-mpm-peruser/usr/sbin/

        dh_fixperms
        dh_strip
        dh_installdocs README
        dh_installchangelogs
        dh_installdeb
        dh_compress
        dh_shlibdeps
        echo "apache:Depends=apache2.2-common (= `dpkg -s apache2.2-common | grep ^Version: | cut -d" " -f2`)" >> debian/apache2-mpm-peruser.substvars
        dh_gencontrol
        dh_md5sums
        dh_builddeb

.PHONY: clean build build-arch binary binary-arch binary-indep

That are all changes we need to make - we can now build the package:

cd ..
dpkg-buildpackage

The package will be available in the /usr/src directory:

cd /usr/src
ls -l
server1:/usr/src# ls -l
total 6512
-rw-r--r-- 1 root src    11392 2007-10-03 19:02 apache2-mpm-itk_2.2.3-01-2.diff.gz
-rw-r--r-- 1 root src      664 2007-10-03 19:02 apache2-mpm-itk_2.2.3-01-2.dsc
-rw-r--r-- 1 root src    29071 2006-10-31 00:04 apache2-mpm-itk_2.2.3-01.orig.tar.gz
drwxr-xr-x 5 root root    4096 2008-08-16 13:40 apache2-mpm-peruser-2.2.3-01
-rw-r--r-- 1 root src      353 2008-08-16 13:36 apache2-mpm-peruser_2.2.3-01-1.dsc
-rw-r--r-- 1 root src      710 2008-08-16 13:40 apache2-mpm-peruser_2.2.3-01-1_i386.changes
-rw-r--r-- 1 root src   165438 2008-08-16 13:40 apache2-mpm-peruser_2.2.3-01-1_i386.deb
-rw-r--r-- 1 root src    50282 2008-08-16 13:36 apache2-mpm-peruser_2.2.3-01-1.tar.gz
-rw-r--r-- 1 root root 6364431 2008-03-22 10:35 apache2.tar.gz
server1:/usr/src#

The mpm-peruser package we've just built is named apache2-mpm-peruser_2.2.3-01-1_i386.deb. Before we can install it, we must uninstall apache2-mpm-prefork as it is conflicting with apache2-mpm-peruser (remember the control file):

apt-get remove apache2-mpm-prefork

server1:/usr/src# apt-get remove apache2-mpm-prefork
Reading package lists... Done
Building dependency tree... Done
The following packages will be REMOVED:
  apache2-mpm-prefork libapache2-mod-php5
0 upgraded, 0 newly installed, 2 to remove and 68 not upgraded.
Need to get 0B of archives.
After unpacking 6115kB disk space will be freed.
Do you want to continue [Y/n]? 
<-- Y
(Reading database ... 29620 files and directories currently installed.)
Removing libapache2-mod-php5 ...
Module php5 disabled; run /etc/init.d/apache2 force-reload to fully disable.
Removing apache2-mpm-prefork ...
Stopping web server (apache2)....
server1:/usr/src#

Unfortunately, this also removes the libapache2-mod-php5 package so that PHP will not work anymore. We will address that in a moment.

Now we can install the apache2-mpm-peruser package:

dpkg -i apache2-mpm-peruser_2.2.3-01-1_i386.deb

Now if you try to reinstall the libapache2-mod-php5 package, you will see that apt insists on removing apache2-mpm-peruser and reinstalling apache2-mpm-prefork which is not what we want - therefore we abort this:

server1:/usr/src# apt-get install libapache2-mod-php5
Reading package lists... Done
Building dependency tree... Done
The following extra packages will be installed:
  apache2-mpm-prefork
Suggested packages:
  php-pear
The following packages will be REMOVED:
  apache2-mpm-peruser
The following NEW packages will be installed:
  apache2-mpm-prefork libapache2-mod-php5
0 upgraded, 2 newly installed, 1 to remove and 61 not upgraded.
Need to get 0B/2833kB of archives.
After unpacking 5681kB of additional disk space will be used.
Do you want to continue [Y/n]? 
<-- n
Abort.
server1:/usr/src#

This happens because when the libapache2-mod-php5 package was built, the maintainer told it that it depends on either apache2-mpm-prefork or apache2-mpm-itk. This means we will have to rebuild the libapache2-mod-php5 from the sources and add the apache2-mpm-peruser package to the dependencies of that package (you can do this with any other package as well if you have the same problem with other packages). I will come to that in a moment.

Share this page:

0 Comment(s)