Lighttpd in chroot…How to get it done…

I was always fascinated by the level of security introduced in Java application servers such as Tomcat, Weblogic and GlassFish, and how the JVM can’t access the outside OS, as well as some other features such as JDBC connection pools etc etc…

Running the web server, and all its components will be similar to Java JVM running and isolated from the existing OS…

Also, running a web server in a chroot() jail can be the ultimate solution for many security issues, including -but no limited to- PHP shells, root kits, back doors, and also have some guarantee that buggy applications (security-wise) won’t impact the entire OS…

Inspired by this post, I’ve made a few modifications to the scripts described and created one more to help in the process…

The whole idea is about creating a new root-like folder structure (/webroot in this example) and fill it only with the needed files and binaries, no bash, no gcc, no RPM, no YUM, and then chroot the web server into this new root…

In this example I’ll be describing how to get this done with Lighttpd + PHP…

1. Lighttpd, get the latest source code, and compile it with /webroot as the prefix

./configure –prefix=/webroot –disable-ipv6 –enable-sendfile64 –with-linux-aio –with-pcre-regex && make && make install

This will install lighttpd in /webroot as its prefix…

2. Install PHP RPMs and MySQL libs into the chroot:

rpm -ivh –relocate=/=/webroot –force \

php-5.1.6-15.Suhosin.i686.rpm \

php-cli-5.1.6-15.Suhosin.i686.rpm \

php-mbstring-5.1.6-15.Suhosin.i686.rpm \

php-common-5.1.6-15.Suhosin.i686.rpm \

php-mysql-5.1.6-15.Suhosin.i686.rpm \

php-pdo-5.1.6-15.Suhosin.i686.rpm \


3. Now create the needed folders for lighttpd operation

mkdir /webroot/var/www/html/www

mkdir /webroot/tmp/

chmod 1777 /webroot/tmp/

mkdir /webroot/etc

mkdir -p /webroot/var/log/lighttpd

chown nobody.nobody /webroot/var/log/lighttpd

mkdir -p /webroot/var/tmp/lighttpd/cache/compress/

chown nobody.nobody /webroot/var/tmp/lighttpd/cache/compress/

cp /etc/hosts /webroot/etc/

cp /etc/nsswitch.conf /webroot/etc/

cp /etc/resolv.conf /webroot/etc/

cp /etc/services /webroot/etc/

cp /etc/localtime /webroot/etc/

mkdir /webroot/var/run

mkdir /webroot/var/run/lighttpd

chown nobody.nobody /webroot/var/run/lighttpd

mkdir -p /webroot/var/www/html

3. So far, you have installed PHP and MySQL libs into this new chroot, but yet, these binaries depend on other libraries that has not been copied yet, the following script will take of this, I call it

   1:  #!/bin/bash
   2:  BASE="/webroot"
   4:  if [ $# -eq 0 ]; then
   5:    echo "Syntax : $0 /path/to/executable"
   6:    echo "Example: $0 /usr/bin/php5-cgi"
   7:    exit 1
   8:  fi
  10:  mkdir -p $BASE$(dirname $1)
  11:  cp $1 $BASE$(dirname $1)
  13:  [ ! $BASE ] && mkdir -p $BASE || : 
  15:  # iggy ld-linux* file as it is not shared one
  16:  FILES="$(ldd $1 | awk '{ print $3 }' |egrep -v ^'\(')"
  18:  echo "Copying shared files/libs to $BASE..."
  19:  for i in $FILES
  20:  do
  21:    d="$(dirname $i)"
  22:    [ ! -d $BASE$d ] && mkdir -p $BASE$d || :
  23:    /bin/cp $i $BASE$d
  24:  done
  26:  # copy /lib/ld-linux* or /lib64/ld-linux* to $BASE/$sldlsubdir
  27:  # get ld-linux full file location
  28:  sldl="$(ldd $1 | grep 'ld-linux' | awk '{ print $1}')"
  29:  # now get sub-dir
  30:  sldlsubdir="$(dirname $sldl)"
  32:  if [ ! -f $BASE$sldl ];
  33:  then
  34:    echo "Copying $sldl $BASE$sldlsubdir..."
  35:    /bin/cp $sldl $BASE$sldlsubdir
  36:  else
  37:    :
  38:  fi

Now you need to invoke this script like this:

./ /webroot/usr/bin/php-cgi

This can apply to any binary file, the script looks up the dependencies via ldd, and copies all the needed files in their rightful location in the new chroot…

Note for MySQL on x86:

You need to do this:

cp usr/lib/mysql/* usr/lib/

4. The other script I created I call it

   1:  #!/bin/bash
   2:  BASE="/webroot"
   4:  if [ $# -eq 0 ]; then
   5:    echo "Syntax : $0 rpm-package"
   6:    echo "Example: $0 php-mysql"
   7:    exit 1
   8:  fi
  10:  FILES="$(rpm -ql $1)"
  12:  echo "Copying shared files/libs to $BASE..."
  13:  for i in $FILES
  14:  do
  15:    d="$(dirname $i)"
  16:    [ ! -d $BASE$d ] && mkdir -p $BASE$d || :
  17:    /bin/cp $i $BASE$d
  19:    LDFILES="$(ldd $i | awk '{ print $3 }' |egrep -v ^'\(')"
  20:          for x in $LDFILES
  21:          do
  22:            echo "Copying $x files/libs to $BASE..."
  23:            y="$(dirname $x)"
  24:            [ ! -d $BASE$y ] && mkdir -p $BASE$y || :
  25:            /bin/cp $x $BASE$y
  26:          done
  27:  done

This script is much like, but this applies to the currently installed RPM in a system that you want to copy into within the chroot…

For example, if you have php-gd RPM installed on the OS, you can copy it into the chroot by when you invoke the script like this:

./ php-gd

In fact you can use it instead of installing the RPMs directly in /webroot (using –relocate) and then do, you can install the RPMs you need normally on the OS, and then chroot them with, I find this more convenient and much less troublesome…

Now all you have to do is create a new lighttpd config file with this line:

server.chroot = "/webroot"

Lighttpd 1.4:

Lighttpd can spawn php-cgi processes on its own if you provide it with some config similar to this

fastcgi.server  = ( ".php" =>

                   ( "localhost" =>


                     "socket" => "/tmp/php-fastcgi.socket",

                     "bin-path" => "/usr/bin/php-cgi", "min-procs" => 1, "max-procs" => 1,





Note that in the config file everything is just as a normal one, except for the chroot line, this means that all the paths are considering /webroot is to be /

In other words, the only line in the config file that refers to /webroot, is the server.chroot line, but nothing else…

Lighttpd 1.5:

Lighttpd can’t spawn php-cgi process, so these need to be done by invoking spawn-fcgi like this:

/webroot/1.5/bin/spawn-fcgi -s /tmp/php-fastcgi1.sock -f /usr/bin/php-cgi -u nobody -g nobody -C 256 -P /var/run/ -c /webroot

Also the only difference here from a normal spawn-fcgi is –c /webroot, and nothing else…

And in lighttpd config:

$HTTP["url"] =~ "\.php$" {

        proxy-core.allow-x-sendfile = "enable",

        proxy-core.protocol = "fastcgi",

        proxy-core.backends = ("unix:/tmp/php-fastcgi1.sock")

        proxy-core.max-pool-size = 256


Now enjoy running lighttpd + PHP in chroot… 😉


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: