Lighttpd logo

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.

🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 80 comments so far... add one
CategoryList of Unix and Linux commands
Disk space analyzersncdu pydf
File Managementcat
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
80 comments… add one
  • Mr Nov 24, 2006 @ 10:09

    Hi, thanks for your great howto but i my phpinfo() i don’t have mysql suppot:

    Configure Command: ‘–without-mysql’


    Thanks for all.

  • 🐧 nixCraft Nov 24, 2006 @ 10:32


    Did you install php4-mysql or php5-mysql package? Use apt-get to install php mysql support package. Next copy shared object to jail (see above for instruction). Restart lighttpd and test it again with phpinfo()

  • Mr Nov 24, 2006 @ 12:52

    hi nixcraft
    thanks to answer, I have done just like you indicate step by step

    apt-get install lighttpd

    (first i installed lighttpd with unstable and later)

    apt-get install php4-cgi php4-cli php4-mysql mysql-server (with stable)

  • 🐧 nixCraft Nov 25, 2006 @ 8:39

    I hope it is working now….

  • Alexander Girao Nov 30, 2006 @ 17:24

    nice work!

    a little tip: instead of using the l2chroot script, you could simply do:

    # ldd usr/bin/php4* | awk ‘{if ($3 ~ /^[^ (]/) print $3}’ | cpio -pdvuL /webroot

    thanks for the nice article!

  • 🐧 nixCraft Nov 30, 2006 @ 18:57


    Nice and dirty one-liner / shell pipe 🙂

    Appreciate your post.

  • contundax Dec 9, 2006 @ 0:27

    I am not sure what happened here:

    /etc/init.d/lighttpd start
    * Starting web server lighttpd Duplicate config variable in conditional 0 global: fastcgi.server
    2006-12-08 16:25:02: (configfile.c.827) source: /etc/lighttpd/conf-enabled/10-fastcgi.conf line: 27 pos: 1 parser failed somehow near here: (EOL)
    2006-12-08 16:25:02: (configfile.c.827) source: /usr/share/lighttpd/ line: 2 pos: 1 parser failed somehow near here: (EOL)
    2006-12-08 16:25:02: (configfile.c.827) source: /etc/lighttpd/lighttpd.conf line: 161 pos: 1 parser failed somehow near here: (EOL)

  • 🐧 nixCraft Dec 9, 2006 @ 0:49


    You have config directive error.

    What versions of OS/distro, and lighttpd do you use?

  • contundax Dec 9, 2006 @ 2:31

    OK, I backed up the original lighttpd.conf and copied the one provided above. Now the db.php link provides:

    Fatal error: Call to undefined function: mysql_connect() in /home/lighttpd/db.php on line 5

  • contundax Dec 9, 2006 @ 2:39

    sorry you asked for my distro and version information as well:

    d# apt-show-versions | grep lighttpd
    lighttpd/edgy uptodate 1.4.13~r1370-1ubuntu1

  • 🐧 nixCraft Dec 9, 2006 @ 10:03

    PHP5 mysql support is not loaded. Try as follows:

    Make sure dir /webroot/etc/php4 exists with php.ini file

    Make sure following files are also copied to /webroot/etc/ directory
    cp /etc/hosts /webroot/etc/
    cp /etc/nsswitch.conf /webroot/etc/
    cp /etc/resolv.conf /webroot/etc/
    cp /etc/services /webroot/etc/

    Make sure you run l2chroot command on and files located in /webroot/usr/lib/php4/2005xxxx directory
    cd /webroot/usr/lib/php4/2005xxxx

    Restart lighttpd and it should work :).

    I have actually updated this tutorial and retested all instructions for Ubuntu Linux 64 bit. It is recommended that you just remove all files from /webroot and just follow tutorial again. Let me know…

  • HostingGeek Dec 19, 2006 @ 1:19

    If your /etc and /webroot/etc are on the same partition, you can also create hardlinks to the files inside the chroot jail. This would be helpful if you ever needed to change the resolv.conf or other files.

  • 🐧 nixCraft Dec 19, 2006 @ 1:25


    No they are not on same partition, this is done for security reason.

    Appreciate your post!

  • amir Jan 12, 2007 @ 18:15

    Why this errors occurs:

    linux:/home/amir# /bin/l2chroot /usr/bin/php5
    (0xffffe000) /lib/tls/ /usr/lib/ /usr/lib/ /lib/ /usr/lib/i686/cmov/ /usr/lib/ /usr/lib/ /lib/ /lib/tls/ /lib/tls/ /lib/tls/ /lib/tls/ /usr/lib/ /usr/lib/ /usr/lib/ /lib/ /usr/lib/ /lib/tls/ /usr/lib/i686/cmov/ /usr/lib/
    cp: cannot stat `(0xffffe000)’: No such file or directory

    need helps

  • 🐧 nixCraft Jan 12, 2007 @ 19:45


    0xffffe000 (related to /lib/ file) is not file so you see the error but script has copied other files. You need to copy /lib/ (32 bit linux) to /webroot/lib directory (see above for cp command).

    I have updated script to fix these warning.

  • TECK Apr 17, 2007 @ 2:26

    I’m trying to run this tutorial on CentOS.
    Everything looks ok, except that the spawn-fcgi cannot be created, even if the /tmp folder is chmomded 777.
    Do I need to apply any patches to lighty? Hope not.
    If you want me to paste my install steps, let me know.

    The funiest part is that you cannot find on Google any other tutorials similar to this one. The CentOS and Lighty forums are totally absent, related to this vital information (setting the chroot).

  • 🐧 nixCraft Apr 17, 2007 @ 9:11


    For CentOS/Fedora/RHEL you need to use different package name and options. If you are using stable 1.4.xx no need to patch up init.d script. For 1.5.xx you need to patch up the init.d script to work.

    Also make sure php compiled or installed as FastCGI (php –v). Let me know if you need detailed instructions regarding CentOS.


  • ali Apr 17, 2007 @ 11:28

    Thanks Vivek for the tutorial, that’s just what I need.

    I have got a question in my mind about accessing my chrooted server trough FTP. I have set up an FTP server (Pure-FTPd) but I can’t cd to the /webroot/home/lighttpd directory because of its permissions. Since it has CHMOD’ed to 0700 only the owner (www-data) can view, write and execute files inside the directory.

    Seems like I have two alternatives to overcome this issue;
    I can configure Pure-FTPd to run as www-data and connect directly with the user www-data. Alternatively, after configuring Pure-FTPd to run as www-data, I may also create a virtual user chroot’ed to /webroot/home/lighttpd as home directory.I can CHMOD /webroot/home/lighttpd to 755, and can access files inside directory via FTP with my unix account.
    Which one is more secure? Or, is any of these solutions rational at all? 🙂

  • ali Apr 18, 2007 @ 16:26

    Another idea;

    I can add my unix user account to group www-data, and CHMOD the /webroot/home/lighttpd to 750. Then I can connect via FTP with my user name and password and can read&write the content inside.

    How about this? 🙂

    PS: Sorry for the messy formating of my previous comment. I have actually used the ul and li tags, but seems like WordPress stripped them.

  • 🐧 nixCraft Apr 18, 2007 @ 18:28


    There are many ways

    Method # 1: Add a user to www-date, and chroot jail the user, use ftpd umask for correct permission

    Method # 2: Use Linux ACL + FTPD chroot jail

    >Which one is more secure?
    ftp Chroot jail, IMPO.


  • ali Apr 20, 2007 @ 7:27

    Thanks for your help Vivek, appreciated. I’ve decided to use your “Method # 1”, which sounds easier to implement.

  • mastr May 8, 2007 @ 16:51

    great article, there are way too few chroot howto’s on the web and hard finding good information about it.

  • magnus Jun 1, 2007 @ 14:28

    I’ve followed this tutorial to the letter multiple times, and I’ve received the same result:

    2007-06-01 10:36:50: (mod_fastcgi.c.1042) the fastcgi-backend /usr/bin/php-cgi failed to start:
    2007-06-01 10:36:50: (mod_fastcgi.c.1046) child exited with status 9 /usr/bin/php-cgi
    2007-06-01 10:36:50: (mod_fastcgi.c.1049) if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.
    You can find out if it is the right one by executing ‘php -v’ and it should display ‘(cgi-fcgi)’ in the output, NOT (cgi) NOR (cli)
    For more information check
    2007-06-01 10:36:50: (mod_fastcgi.c.1351) [ERROR]: spawning fcgi failed.
    2007-06-01 10:36:50: (server.c.849) Configuration of plugins failed. Going down.

    Recently, lighttpd has been running flawlessly on my system. It’s only when I attempt to jail it that I receive these errors.

  • 🐧 nixCraft Jun 1, 2007 @ 21:12

    Did you installed php4-cgi or php5-cgi package? If not plz install the same. If it is installed open lighttpd file find line
    and replace it with

  • magnus Jun 3, 2007 @ 22:47

    I’m using the php5-cgi package. I replaced /usr/bin/php-cgi with /usr/bin/php5-cgi and I still receive the same error.

  • TECK Jun 12, 2007 @ 19:28

    Hi Vivek,

    >> Let me know if you need detailed instructions regarding CentOS.
    You can give me some guidance, no need to be super detailed. Basically is the same like your tutorial except you use php instead of php and /modules instead /20050606…

    Let me know what other steps you take. Thanks.

  • 🐧 nixCraft Jun 12, 2007 @ 20:41


    Only path and file names are changed so if you have a little experience with Linux, you should able to chroot php

  • Zoran Jun 13, 2007 @ 19:35


    I also get error msg when testing db.php:

    Fatal error: Call to undefined function: mysql_connect() in /var/www/db.php on line 5

    I followed all steps, but no luck for mysql.

    btw I cannot find file ? where it should be?

  • radeone Jul 3, 2007 @ 1:52

    how would you configure rails with this type of setup because im having a hard time getting it to work.

  • Shoghi Aug 13, 2007 @ 22:21

    I have used this procedure on fedora core 4 using php5 and worked ok!

    I just changed the lighttpd configuration file to point to the actual directory of php-cgi.

    I got the PHP error about the fcgi, after a while I used strace to get some answers. The error was unable to load the mysql client library. I made a soft link to the mysql client library in the lib directory (inside the webroot jail of course, l2chroot copied it to the /webroot/usr/lib/mysql) and the problem was fixed.

  • tomcat Aug 21, 2007 @ 22:32

    I got always this Error:
    Warning: mysql_select_db() [function.mysql-select-db]: Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (40) in /home/lighttpd/db.php on line 6

    I Try to let php/lighttpd use TCP and noch Socket but it dosnt work 🙁

  • J2S Sep 23, 2007 @ 7:50

    Hi Vivek, first let me say thank you for all your hard work, it has helped me in abundance :).

    My problem is I am trying to chroot on CentOS 4.5 and have adapted your tutorial somehwat however when I reach finding it can’t be found because I’m using php5 and apparently mysql extension is noy bundled with php anymore. I do have mysql installed however as I installed from source but still there is no

    Is it possible to get some advice here and if you have time CentOS tutorial? Many thanks.

  • 🐧 nixCraft Sep 24, 2007 @ 3:42


    Under CentOS you need to install php-mysql binary package

  • Zeng Oct 12, 2007 @ 18:35

    I have the same error as the person above:

    Warning: mysql_pconnect() [function.mysql-pconnect]: Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2)

    Mysql is running in its own chrooted environment. Is there any solution except creating a hardlink?

  • 🐧 nixCraft Oct 12, 2007 @ 19:17


    My MySQL also run in chrooted jail and I connect it via loopback IP port 3306.


  • twinrix Nov 3, 2007 @ 9:07

    Hi nice howto!

    I am running a Debian Etch amd64 distri and did exactly the same as in this howto. Ok I admit I used php5. 🙂

    The db.php works fine if I use my local mysql server, but if I try to connect to another server, I get the following error message:

    Warning: mysql_connect() [function.mysql-connect]: Lost connection to MySQL server at ‘reading initial communication packet’, system error: 111 in /home/lighttpd/db.php on line 5

    Futhermore, I am having trouble with DNS; which means if I use it will not find it.

    And yes I have copied all necessary files.

    It would be great if anyone had an idea.


  • 🐧 nixCraft Nov 3, 2007 @ 14:27


    I don’t have problem connecting mysql hosted on pnet (private IP on same network but w/o public connectivity). Make sure resolv.conf and binary libs are copied. Also if you have problem run strace from chroot to debug exact problem.

  • twinrix Nov 3, 2007 @ 16:44

    hi vivek,

    thank you soooo much!!!
    I was able to detect a couple of missing libs and just copied them by hand.


  • Dougal Nov 5, 2007 @ 21:06

    I get:

    Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’

    when I try to run db.php

    When I tried following the instructions in the strace from chroot link, all I got is “php command not found”.

    Can anyone suggest anything? I’m a bit of a newbie :/

  • Dougal Nov 5, 2007 @ 23:01

    Oops, I solved that little problem, then, by running the command with php5 instead of php, but now I’m not sure what to do with the output of debug.txt…

    There are lots of libraries being listed and most of them seem to be in webroot already.

  • 🐧 nixCraft Nov 6, 2007 @ 9:20


    Use l2chroot to copy all shared libs.


  • Dougal Nov 6, 2007 @ 19:37

    thanks, but I’m not sure how to do that? I already tried following the instructions in the tutorial for copying shared libs. How do I know what other libs are shared?

  • Dougal Nov 6, 2007 @ 21:04

    I think I have all the libraries copied, but I still get “lost connection” when connecting…

    Warning: mysql_connect() [function.mysql-connect]: Lost connection to MySQL server during query in /home/lighttpd/ on line 5

  • Dougal Nov 6, 2007 @ 21:37

    when running strace it says:

    Fatal error: Call to undefined function mysql_connect()

    And no libs appear to be missing except for, but that can’t be the problem because I just don’t have that lib at all, and the script runs fine outside of chroot.

  • Arnaud D Dec 3, 2007 @ 0:37

    Installation went fine on CentOS, I didnt know that was so simple to chroot myslq php like that just by copying libs, great tut

  • Arnaud D Dec 3, 2007 @ 12:15

    I just have one trouble using chroot on CentOS, each time I stop the service its FAILED for stopping the lighttpd pid, but it stops the spawn-fcgi process correctly, any idea what do I need to upgrade ?
    Im using the modded init.d/lighttpd

    start() {
    echo -n $”Starting $prog: ”
    daemon $lighttpd -f $LIGHTTPD_CONF_PATH
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
    /usr/local/bin/spawn-fcgi -s /chroot/tmp/heap.socket -f /chroot/usr/bin/php-cgi -u -g -C 5 -P /tmp/
    chmod 0777 /chroot/tmp/heap.socket
    return $RETVAL

    stop() {
    echo -n $”Stopping $prog: ”
    # MYPID=`cat “/tmp/” 2>/dev/null `
    # /bin/kill “$MYPID” >/dev/null 2>&1
    killproc $lighttpd
    killproc php-cgi
    [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
    [ -f /tmp/heap.socket ] && /bin/rm -f /tmp/heap.socket || :
    [ -f /tmp/ ] && /bin/rm -f /tmp/ || :
    chmod 0777 /chroot/tmp/heap.socket
    return $RETVAL

    Please help

  • Arnaud D Dec 3, 2007 @ 16:21

    Ok I have fixed several probs with CentOS,

    If you use spawn-fcgi you will have to:

    mkdir /webroot/bin
    cp /bin/sh /webroot/bin/
    l2chroot /webroot/bin/sh

    This has been discussed here

    and so PHP is looking for the mysql.sock file in /var/lib/mysql/mysql.sock

    so open my.cnf

    just change the line

    socket = /var/lib/mysql/mysql.sock

    to socket = /webroot/var/lib/mysql/mysql.sock


    mkdir -p /webroot/var/lib/mysql/
    chown mysql:mysql /webroot/var/lib/mysql/
    /etc/init.d/mysqld restart

    and modify in /etc/init.d/lighttpd the spawn-fcgi line to have the option “-c /chroot”

    After that I still need help here because I can start services , but when stopping lighttpd and php-cgi are reported [FAILED] and I can only killall manually wich is boring, thanks 🙂

  • Arnaud D Dec 3, 2007 @ 17:26

    Ok good news , I fixed the start/stop problem, just make sure the pids are in the /var/run directory, not much , and edit the init.d/lighttpd script by renaming the occurence to because the living process is recognized under “php-cgi” name 🙂

  • Arnaud D Dec 4, 2007 @ 14:36

    To note that if you have the /bin/sh problem to put in the /chroot jail this has been fixed in svn 2026

    instead of to use spawn-fcgi -f [binary] put -f [binary]at the end of the line and replace -f by —

  • Ulrich Dec 7, 2007 @ 21:04

    Thanks for this great tutorial. Works perfectly with Ubuntu + PHP5 + Perl. But I have one question:
    The lighttpd executable is not called from the jail. Would it be possible for an attacker to exploit lighttpd directly (not PHP or Perl) and gain access to the system?

  • Piotr Jan 23, 2008 @ 19:31

    Great article!

    On some Debian servers you need to copy also library:

    cp /lib/ /webroot/lib/

    Without that your chrooted apps (including php) won’t be able to access host by hostnames:

    /webroot/var# chroot /webroot curl -I “”
    curl: (6) Couldn’t resolve host ‘’

    Best regards

  • gawwdotnet Mar 26, 2008 @ 22:53

    I took this tutorial, and made a script out of it. Thought I would share since it was very helpful. You can alter /etc/php5 and re-run the script, it will update the dir, etc..

    From a fresh Ubuntu install, after installing the appropriate packages and running this script I find all I need to do is setup the lighttpd home directories. 🙂

    See my script –

  • daddelkopp Apr 10, 2008 @ 6:39

    I used this tutorial with Debian Etch rc3 and PHP5. It works fine until I want to use php fastcgi. After enable FASTCGI with “lighty-enable-mod fastcgi”, I changed /etc/lighttpd/conf-enabled/10-fastcgi.conf:

    FROM:"bin-path" => "/usr/bin/php4-cgi",
    "socket" => "/tmp/php.socket",

    TO:"bin-path" => "/webroot/usr/bin/php5-cgi",
    "socket" => "/webroot/tmp/php.socket",

    After restart lighttpd I get an error message:
    “unix: /webroot/tmp/php.socket could not be found or is not writeable”

    The folder /webroot/tmp is chmood 1777 and owned by root:root. What did I do wrong? I performed this howto twice with a fresh debian installation. The folder /webroot is a partition mapped by fstab. Could that be the problem?

  • 🐧 nixCraft Apr 10, 2008 @ 6:42


    Under chroot jail you cut /webroot dir as it is changed to / – so try as follows and restart lighttpd:
    "bin-path" => "/usr/bin/php5-cgi",
    "socket" => "/tmp/php.socket",

  • daddelkopp Apr 10, 2008 @ 7:00

    Thanks for your fast replay vivek. In this case lighttpd report 4 errors. It could not start/find 4 .pdo files (mysql,mysqli…). Because Iam not at home, I could not write the correct error message. I will try it in the evening again.

    Thanks for your time and work

  • daddelkopp Apr 10, 2008 @ 19:32

    The last error was, that I forgot to copy some php libs. Everything is fine now 🙂

  • Mike Apr 30, 2008 @ 13:11


    I’m getting this:

    ~# dpkg -L php5-mysql

    I guess I can just adapt it with the given names above? Are there other little hitches on a current Debian Etch system? Is it possible to put 'Tomcat' in jail too? Thank you so much for this great website!!

  • Mike Apr 30, 2008 @ 13:30

    The step when you create ‘/var/www/’ and ‘/var/run/’ within webroot is missing.

    I’m getting this after step 5:

    /etc/init.d/lighttpd start
    Starting web server: lighttpd2008-04-30 03:24:03: (configfile.c.1114) base-docroot doesn't exist: /webroot/var/www/
    2008-04-30 03:24:03: (server.c.564) setting default values failed

  • 🐧 nixCraft Apr 30, 2008 @ 13:53


    Yes, you need to use current path:


    You can run almost anything in jail including tomcat, python and other stuff. All you have to do is copy required to jail.

    > base-docroot doesn’t exist: /webroot/var/www/

    You need to follow modified lighttpd.conf file. In jail /webroot/var/www becomes /var/www only. This tutorial changes /var/www to /home/lighttpd/ Refer config file.

  • Mike Apr 30, 2008 @ 14:03

    Ahhh…now I see. The step where you have to create the ‘/var/www’ and the ‘/var/run’ within the /webroot is missing in this tutorial. Thanks for the fast reply! However, if I start lighty I get a bunch of errors (spawning fcgi etc.), I’m now very insecure, I guess i leave it alone as I’m not enough experienced to adapt it to Debian Etch 4, MySQL5, PHP5 and Tomcat5 (in the end I make somewhere a mistake and it’s not more secure then before). 🙁

  • Mike Apr 30, 2008 @ 14:51

    Hmmm…I guess I got it. I had to copy the ‘’ file to, which was not showing with ‘dpkg -L php5-mysql’ 🙂

  • Mike Apr 30, 2008 @ 16:14

    Question: What about the ‘*.pid’ files? Can they stay where they are or do I have to copy them into the jail too?

  • mdev Jul 20, 2008 @ 11:59

    Thanks although some things do not work when using your tutorial and need changes I got it running and learned alot on trial and error.

  • niyo Mar 18, 2009 @ 2:35


    Can this chrooted setup be managed by cpanel or ispconfig?


  • Janez Dolinar Apr 17, 2009 @ 10:13

    (i know this is an old reply but I had the same problem)

    @magnus: make sure, you copied files correctly. In my case I had /webroot/lib64 as a file!

  • L1ttl3J1m Apr 30, 2009 @ 9:53

    For $DEITY’s sake, don’t approve that last one 🙂 Try this one instead.

    I had some trouble getting it to work, but here’s some stuff I worked out.

    For missing libraries ( you can do this;

    ldd ./ – Which you can find by looking in the PHP error log. I found it especially good for this one;

    PHP Startup: Unable to load dynamic library ‘’ – File not found in Unknown on line 0

    So do an LDD on that file (ldd ./ (be in the directory where the file is, of course)) and it outputs the libraries that that extension needs to run – scatter those around in the jail versions of /lib, /opt/lib, usr/lib, /usr/local/lib, and those errors stop happening.

    For the ones that it didn’t make go away (I’m looking at you, MySQL!), doing;

    ldconfig -p | grep (name of broken process**)

    will give you a few more to copy across.

    The thing that I was wondering about though, is how to go about securing that tmp folder. I don’t like the idea of having a world-executable folder on my server, no matter how jailed it is.

    Any ideas?

    *Make sure you don’t forget to set that one to a path that’s inside the jail, too, otherwise PH can’t write to it and you’ll never see these handy-dandy helpful messages. ***

    ** MySQL, grep bz for bzip & bzip2, for example – one for each extension that’s in your PHP.ini file, basically.

    *** That’s sarcasm, by the way. File not found in Unknown at line 0, yeah that’s helpful!

  • maxBirdy Nov 9, 2009 @ 1:35

    i run through this whole tutorial

    i make sure that /home/lighttpd/ is the root dir

    and that /webroot is the chroot jail

    then i restart lighty

    all is good, and it restarts without any errors

    then i type in,, or, firefox goes “Firefox can’t establish a connection to the server at x.x.x.x” my port 80 is forwarded, but when i go to, it says port 80 is not in use.

    i run ps aux in bash shell, i see nothing that says “lighttpd”

    im using php5, mysql 5.1, and lighttpd 1.4.23

    wtf is wrong with my setup, just because my software is newer shouldnt change anything right?

    the.conf files for lighty on this site, and mine, are identical, in configuration, but mine has a few other settings that are commented out so i just leave them be.

    i have even checked my error logs, not a damn thing is in them

    and ive checked my network configuration, all is well there too.

    plllleeeeeeeaaaaaaaasssssseeeeeeeeeee help, im really lost and frustrated.

  • mandible Jan 5, 2010 @ 0:45

    this website sucks, typical linux users who dont give a shit about noobies who need help, this tutorial doesnt work. install latest debian, and use php5 instead of 4, and follow this tutorial, it doesnt work.

  • grand wazoo Jan 29, 2010 @ 16:39

    If you’re a “noobie who need[s] help,” then you shouldn’t be preparing an externally facing chroot’ed security-critical linux web server installation. Pay someone to do this for you. Security is really, really, really hard. Buck up.

  • SilentHunter Mar 12, 2010 @ 16:51

    Sorry but again to this problem:

    I used this tutorial with Debian Etch rc3 and PHP5. It works fine until I want to use php fastcgi. After enable FASTCGI with “lighty-enable-mod fastcgi”, I changed /etc/lighttpd/conf-enabled/10-fastcgi.conf:

    “bin-path” => “/usr/bin/php4-cgi”,
    “socket” => “/tmp/php.socket”,

    “bin-path” => “/webroot/usr/bin/php5-cgi”,
    “socket” => “/webroot/tmp/php.socket”,

    After restart lighttpd I get an error message:
    “unix: /webroot/tmp/php.socket could not be found or is not writeable”

    Is there a better solution than cutting the /webroot? I get the same error with the socket but without the /webroot it wouldn’t work anyway….

  • james Apr 12, 2010 @ 9:52

    Hi. I have followed carefully each steps and I received this error when starting lighttpd:

    (mod_fastcgi.c.1042) the fastcgi-backend /usr/bin/php-cgi failed to start:
    (mod_fastcgi.c.1046) child exited with status 9 /usr/bin/php-cgi
    (mod_fastcgi.c.1049) if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.
    You can find out if it is the right one by executing ‘php -v’ and it should display ‘(cgi-fcgi)’ in the output, NOT (cgi) NOR (cli)

    lighttpd has been working fine before I wanted to put it in jail. whenever I comment out the server.chroot line. everything works ok.

    i have set correctly /usr/bin/php-cgi correctly to /usr/bin/php5-cgi but still the same error.

  • lfitz Jun 16, 2010 @ 1:31

    hi, i get 403 – forbidden errors for db.php and test.php, how can i fix this?

  • Julien Aug 29, 2010 @ 19:58

    Thanks for the howto, I used it as a based to my own script that chroot nginx and php on Debian. I believe it might be of interest to some of the readers here, so here is the link.

  • Christoph Dec 6, 2010 @ 17:14

    nice tutorial

    The default path of the compress cache directory in Debian is now “/var/cache/lighttpd/compress/”.

    So the diretory “/webroot/var/cache/lighttpd/compress/” should exists to work (instead of the directory in the tutorial). 😉

  • jh Dec 16, 2010 @ 2:49

    Followed the guide to put my lighttpd server into jail. All working fine except DNS resolution not working in chroot jail. Turn out I have to copy both and from /lib to /webroot/lib. Great guide.

  • maximebuy Apr 13, 2011 @ 22:48

    I followed the instruction and got 400 error also. Then I made the following changes:
    1. change the base dir in /etc/lighttpd/lighttpd.conf from /var/www to /home/lighttpd
    2. change the cache dir from /webroot/var/tmp/lighttpd/cache/compress/ to /webroot/var/cache/lighttpd/compress/
    3. change the /etc/lightpd/conf-enablede/10-fastcgi.conf, where /usr/bin/php-cgi to /usr/bin/php5-cgi

    Then I can open the db.php and test.php, my system is “PHP Version 5.2.6-1+lenny10”.

    After these three steps, there are still some error in output of db.php, just see the log file in /webroot/var/log/lighttpd/error.log and check the errors.

  • none-101 Oct 17, 2011 @ 15:01

    Where do you put the static web files that one wishes to serve?
    I have these on /www/ Is it possible, using your set-up above to still server from /www. These are on different partitions.


  • Nguyen Thanh Binh Jun 5, 2013 @ 9:32

    Thanks for your the article… It’s very great.

  • tuxd3v Feb 2, 2017 @ 14:26

    Only to share a remake of your script:

    # Use this script to copy shared (libs) files to SSH/SFTP chrooted jail Server
    # ----------------------------------------------------------------------------
    # Written by nixCraft
    # (c) 2006 nixCraft under GNU GPL v2.0+
    # + Added ld-linux support
    # + Added error checking support
    # 2016/11/11
    # Changed by Carlos Domingues
    # (c) 2016 Carlos Domingues under  GNU GPL v2.0+
    #  + Reporting actions is now better.
    #  + All Operations are now done, in a simple 'for cycle'...
    # ------------------------------------------------------------------------------
    # See url for usage:
    # -------------------------------------------------------------------------------
    # Set CHROOT directory name
    # -------------------------------------------------------------------------------
    if [ $# -eq 0 ]; then
      echo "Syntax : $0 /path/to/executable"
      echo "Example: $0 /usr/bin/php5-cgi"
      exit 1
    [ ! -d $BASE ] && mkdir -p $BASE || :
    FILES="$(ldd $1 | awk '{if($3 ~/^// && $2 ~/^=>/ ){print $3;}else{ if($1 ~/^// && $2 ~/^(/ )print $1;}}')"
    #echo "Copying shared files/libs to $BASE..."
    for i in $FILES;do
            echo "Copying $i shared files/libs to $BASE..."
            d="$(dirname $i)"
            [ ! -d $BASE$d ] && mkdir -p $BASE$d || :
            /bin/cp -pv $i $BASE$d

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum