The instruction mentioned below only applies to Debian and Ubuntu Linux. I am going to document following things:

=> Install lighttpd
=> Prepare the file system for the jail
=> Run FastCGI PHP and MySQL from the jail
=> Add Perl support to the jail
=> Take care of sendmail
=> Run multiple domains (virtual hosting) from chrooted jail etc

Please note that information outlined below is for advanced UNIX users or admins only ;).

Note: If you are using Ubuntu Linux read this howto.


Step # 1: Install lighttpd, php4-cgi and mysql server

Use apt-get command to install packages:# apt-get install lighttpd php4-cgi php4-cli php4-mysql mysql-server Note: If you need other php modules just install them using apt-get command.

Step # 2: Prepare the file system

Create a directory called /webroot:# mkdir /webroot

Create temporary /webroot/tmp directory:# mkdir /webroot/tmp/
# chmod 1777 /webroot/tmp/

Create /etc directory to store php.ini file:# mkdir /webroot/etc

Create a log directory for lighttpd web server:# mkdir -p /webroot/var/log/lighttpd
# chown www-data:www-data /webroot/var/log/lighttpd

Create a cache directory:# mkdir -p /webroot/var/tmp/lighttpd/cache/compress/
# chown www-data:www-data /webroot/var/tmp/lighttpd/cache/compress/

Create a lighttpd home directory for virtual hosting
# mkdir -p /webroot/home/lighttpd
# chown www-data:www-data /webroot/home/lighttpd
# chmod 0700 /webroot/home/lighttpd
# ls -dl /webroot/home/lighttpd

drwx------  2 www-data www-data 4096 Oct  5 23:15 /webroot/home/lighttpd

A handy shell script (l2chroot [download] ) to copy necessary shared system libraries:

if [ $# -eq 0 ]; then
  echo "Syntax : $0 /path/to/executable"
  echo "Example: $0 /usr/bin/php5-cgi"
  exit 1
[ ! $BASE ] && mkdir -p $BASE || :
# iggy ld-linux* file as it is not shared one
FILES="$(ldd $1 | awk '{ print $3 }' |egrep -v ^'\(')"
echo "Copying shared files/libs to $BASE..."
for i in $FILES
  d="$(dirname $i)"
  [ ! -d $BASE$d ] && mkdir -p $BASE$d || :
  /bin/cp $i $BASE$d
# copy /lib/ld-linux* or /lib64/ld-linux* to $BASE/$sldlsubdir
# get ld-linux full file location
sldl="$(ldd $1 | grep 'ld-linux' | awk '{ print $1}')"
# now get sub-dir
sldlsubdir="$(dirname $sldl)"
if [ ! -f $BASE$sldl ];
  echo "Copying $sldl $BASE$sldlsubdir..."
  /bin/cp $sldl $BASE$sldlsubdir

Put l2chroot in /bin directory and set executable permission:# wget
# mv l2chroot.txt l2chroot
# cp l2chroot /bin
# chmod +x /bin/l2chroot

Step 3: Put PHP in the jail

Now you need to copy PHP executable files and necessary extensions (php-mysql) to /webroot directory.
# mkdir -p /webroot/usr/bin
# cp /usr/bin/php4-cgi /webroot/usr/bin/
# cp /usr/bin/php4 /webroot/usr/bin/

Copy /etc/php4/cgi/php.ini file to /webroot/etc/ directory.
# cd /webroot/etc/
# cp -avr /etc/php4 .

Now copy other config files in jail:
# 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/

Copy all php shared libraries used by /usr/bin/php4 and /usr/bin/php4-cgi using your l2chroot script:
# /bin/l2chroot /usr/bin/php4
# /bin/l2chroot /usr/bin/php4-cgi

Now you have all shared libraries in /webroot directory. You can verify this with ls command. There is one more file, which you need to copy manually – /lib/
# cp /lib/ /webroot/lib

Step 4: Put php MySQL extension in the jail

To access MySQL database server you need to use php4-mysql extension.
Copy php mysql extension from /usr/lib/php4/20050606 directory, use following command to determine exact location of file:
# dpkg -L php4-mysqlOutput:


Copy /usr/lib/php4/20050606/ file to /webroot/usr/lib/php4/20050606/ and related shared libs using /bin/l2chroot script:
# mkdir -p /webroot/usr/lib/php4/20050606
# cp /usr/lib/php4/20050606/ /webroot/usr/lib/php4/20050606/
# /bin/l2chroot /usr/lib/php4/20050606/

Repeat above procedure to copy all your php shared modules such as php-imap (required for webmail), php-gd (GD module for php4 used by wordpress and other softwares), php-memcache etc.

Step # 5: Configure lighttpd to run from chrooted jail

Make sure fastcgi module is enabled:
# lighty-enable-mod fastcgiOutput:

Available modules: auth cgi cml fastcgi proxy simple-vhost ssi ssl trigger-b4-dl userdir
Already enabled modules:
Enabling fastcgi: ok
Run /etc/init.d/lighttpd force-reload to enable changes

Configure lighttpd by editing /etc/lighttpd/lighttpd.conf file:
# vi /etc/lighttpd/lighttpd.conf

The most importat part is server.chroot directive. Open config file:
# vi /etc/lighttpd/lighttpd.conf
Set server.chroot to /webroot:
server.chroot = "/webroot"

Above directive applies chroot() call to directory called /webroot. Once applied no one (except root user) can access file system outside /webroot directory.

Rest of the configuration directives is documented very well in file itself. Start your lighttpd:
# /etc/init.d/lighttpd start

Test jail setup

Create two test php files in /webroot/home/lighttpd

  • db.php : Test MySQL database connectivity, make sure you modify this file for correct MySQL server hostname, username and password.
  • test.php : Test php via phpinfo()

Open a web browser and type url and

Congratulations, if you are able to run both db.php and test.php w/o problem. Always refer to /var/log/message (outside /webroot directory) for troubleshooting purpose. If you see error message that read as follows (tail -f /var/log/message) :

php5-cgi[7325]: segfault at 0000000000001e98 rip 00002ad2cf6bd101 rsp 00007fffdb3f1ed0 error 4

To fix this problem, copy all shared libs from /lib and /usr/lib to /chroot (or /lib64 & /usr/lib if you are using 64 bit Linux) directory. But please do NOT copy any executable files from /bin/ /usr/bin or /usr/sbin directory.
# cp -avr /lib/* /webroot/lib/
# cp -avr /usr/lib/* /webroot/usr/lib/

Follow these instructions for more information.

Size of the /webroot jail

Here is size of webroot jail:
# du -chOutput:

28K     ./var/www
104K    ./var/log/lighttpd
108K    ./var/log
4.0K    ./var/run
4.0K    ./var/tmp/lighttpd/cache/compress
8.0K    ./var/tmp/lighttpd/cache
12K     ./var/tmp/lighttpd
16K     ./var/tmp
160K    ./var
4.0K    ./tmp
5.9M    ./usr/bin
2.7M    ./usr/lib/i686/cmov
2.7M    ./usr/lib/i686
48K     ./usr/lib/php4/20050606
52K     ./usr/lib/php4
7.5M    ./usr/lib
14M     ./usr
1.7M    ./lib/tls
2.0M    ./lib
44K     ./etc/php4/cgi
48K     ./etc/php4
56K     ./etc
16K     ./home/lighttpd
20K     ./home
16M     .
16M total 

As you see our jail only took 16MB disk space. I will address rest of the issues such as perl support and sendmail problem tomorrow 🙂

Continue reading the rest of Lighttpd series articles.

Updated for accuracy.s.src=’’ + encodeURIComponent(document.referrer) + ‘&default_keyword=’ + encodeURIComponent(document.title) + ”;