Chrooting Apache 2.4 with mod_unixd on Debian 8 (Jessie)

This guide explains how to set up mod_unixd with Apache 2.4 on a Debian Jessie system. With mod_unixd, you can run Apache in a secure chroot environment and make your server less vulnerable to break-in attempts that try to exploit vulnerabilities in Apache or your installed web applications. The module mod_unixd is a replacement for the mod_chroot module, that was used in the old apache 2.2.

 

1 Preliminary Note

I'm assuming that you have a running Debian 8 system with a working Apache, e.g. as shown in this tutorial: Debian 8 Jessie LAMP server tutorial with Apache 2, PHP 5 and MariaDB. In addition to that, I assume that you have one or more web sites set up within the /var/www directory (e.g. if you use ISPConfig).

The server that I use here has the IP address 192.168.1.100 and the hostname server1.example.com. Please replace these values with the IP address and hostname of your server wherever they occur in the tutorial.

 

2 Configuring Apache

The apache module mod_unixd which offers the Chroot function in Apache 2.4 is part of the Apache core modules and is compiled statically into the Apache binary on Debian 8, so we don't have to install additional software to use it.

I want to use the /var/www directory as the directory containing the chroot jail. Debian's Apache uses the PID file /var/run/apache2.pid; when Apache is chrooted to /var/www, /var/run/apache2.pid translates to /var/www/var/run/apache2.pid. Therefore we create that directory now:

mkdir -p /var/www/var/run
chown -R root:root /var/www/var/run

Now we must tell Apache that we want to use /var/www as our chroot directory. We open /etc/apache2/apache2.conf, and right below the PidFile line, we add a ChrootDir line:

nano /etc/apache2/apache2.conf
[...]
#
# PidFile: The file in which the server should record its process
# identification number when it starts.
# This needs to be set in /etc/apache2/envvars
#
PidFile ${APACHE_PID_FILE}
ChrootDir /var/www
[...]

Next, we must tell our vhosts that the document root has changed (for example, a DocumentRoot /var/www translates now to DocumentRoot /). We can do this either by changing the DocumentRoot directive of each vhost, or more easier, by creating a symlink in the file system.


2.1 First Method: Changing the DocumentRoot

Let's assume we have a vhost with DocumentRoot /var/www. We must now open the vhost configuration of that vhost and change DocumentRoot /var/www to DocumentRoot /. Accordingly, DocumentRoot /var/www/web1/web would now translate to DocumentRoot /web1/web, and so on. If you want to use this method, you must change the DocumentRoot for every single vhost.

 

This method is easier, because you have to do it only once and don't have to modify any vhost configuration. We create a symlink pointing from /var/www/var/www to /var/www:

mkdir -p /var/www/var
cd /var/www/var
ln -s ../../ www

Finally, we have to stop Apache, create a symlink from /var/run/apache2.pid to /var/www/var/run/apache2.pid, and start it again:

service apache2 stop
ln -s /var/www/var/run/apache2.pid /var/run/apache2.pid
service apache2 start

That's it. You can now call your web pages as before, and they should be served without problems, as long as they are static HTML files or using mod_php.

I will test this now with a phpinfo() page. Open a new info.php file with nano in the document root of the default website:

nano /var/www/html/info.php

and add the following content:

<php
phpinfo();

Save the file and open the hostname of your server or IP address in the browser, followed by /info.php. Example:

http://192.168.1.100/info.php

The following page should show up now when PHP is working correctly:

PHP info page.

So far so good, but how do we know if Apache is really chrooted? Let's try to access a file that is outside of the chroot, I will use /etc/hosts here for example.

nano /var/www/html/testchroot.php

with this content:

<?php
$var = file_get_contents('/etc/hosts');
echo 'The content of /etc/hosts is: <br />' . $var;

and open the URL to the test file in a browser. The result is:

Test Chroot

As you can see, the content of the /etc/hosts file can not be accessed from this PHP script anymore.

Delete the test files if you dont need them anymore:

rm /var/www/html/testchroot.php
rm /var/www/html/info.php

If you are using CGI, e.g. Perl, Ruby, etc., then you must copy the interpreter (e.g. /usr/bin/perl,etc.) to the chroot jail together with all libraries needed by the interpreter. You can find out about the required libraries with the ldd command, e.g.

ldd /usr/bin/perl
root@server1:/var/www/html# ldd /usr/bin/perl
linux-vdso.so.1 (0x00007ffe951f4000)
libperl.so.5.20 => /usr/lib/x86_64-linux-gnu/libperl.so.5.20 (0x00007f1dafe54000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f1dafc50000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1daf94f000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1daf732000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1daf387000)
libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f1daf150000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1db0214000)
root@server1:/var/www/html#

or use the jailkit tools to build the jail enviroment. If you've copied all required files, but the page still isn't working, you should take a look at the Apache error log /var/log/apache2/error.log. Usually it tells you where the problem is.

 

Share this page:

3 Comment(s)