chroot lighttpd with PHP5 and MariaDB

Instructions for running lighttpd in a chrooted environment, along with PHP5-FCGI and MariaDB support (may also work with MySQL).
Inspired by sparse documentation, compiled from different sources, adapted and updated where necessary.
Heavily based from NixCraft and mylinuxtips.info setup guides.

I am not liable for any damage or harmed kittens this howto makes upon you. If you are successful, congratulations.

Environment: Debian 7 x86_64

Requires

  • MariaDB repository (instructions here)
  • l2chroot (here)
  • lighttpd, PHP5, MariaDB, and dependencies installed.

Procedure

Instructions require root most of the time; used sudo -s for convenience. Prepending sudo before each command is fine.

Installation

Update apt database and install lighttpd, PHP5 (and extensions), MariaDB, and dependencies.
apt-get update; apt-get install lighttpd php5-cgi php5-gd php5-mysqlnd php5-xcache mariadb-server

Preparing chroot environment

Make a folder somewhere in your server that will hold lighttpd’s chrooted environment. Files to be placed here are the bare minimum that lighttpd needs to run and function properly. In this example, I will use /lightyroot

Create necessary folders needed for chroot.

mkdir /lightyroot
cd /lightyroot
mkdir -p etc/php5 var/{cache/lighttpd/uploads,cache/lighttpd/compress,log/lighttpd,run/mysqld,run/lighttpd,lib/php5,www} usr/{share,bin,lib} tmp lib lib64

Copy files needed by lighttpd and PHP5.
Note: Your current working directory is still at /lightyroot

cp -Rpv /etc/{hosts,locale.alias,locale.gen,localtime,nsswitch.conf,php5,resolv.conf,services} etc/
cp -Rpv /usr/bin/php5-cgi /etc/alternatives/php-cgi usr/bin/
cp -Rpv /usr/share/xcache usr/share/
cp -Rpv /usr/lib/php5 usr/lib/

Preparing lighttpd and PHP5 config

Stop MariaDB and lighttpd
service lighttpd stop
service mysql stop
Edit /etc/lighttpd/lighttpd.conf with your favorite editor and add the following line.

server.chroot = "/lightyroot"

Save and close. This tells lighttpd to chroot to /lightyroot on startup.
Enable PHP-FCGI support for lighttpd
lighttpd-enable-mod fastcgi fastcgi-php

Edit /lightyroot/etc/php5/cgi/php5.ini and uncomment (and/or set)
cgi.fix_pathinfo=1
Save and close.

Don’t start lighttpd or mysql yet.

Copy shared library dependencies

Plugins at /lightyroot/usr/lib/php5/20100525/ depend on libraries located outside the chroot. This procedure will copy those dependencies into the chroot environment.
cd /lightyroot/usr/lib/php5/20100525
and run l2chroot on every *.so there. Alternatively, you can try this little loop. Make sure your current working directory is at /lightyroot/usr/lib/php5/20100525

#!/bin/bash
for SHOBJ in $(ls *.so)
do
l2chroot $SHOBJ
done

This iterates through each *.so file in the current directory. In this case, at /lightyroot/usr/lib/php5/20100525.

Adjust permissions

Once the necessary folders are copied, time to adjust permissions and avoid some head-scratching problems.
cd /lightyroot
chown -R www-data:www-data usr/lib/php5 var/{cache/lighttpd,log/lighttpd,run/lighttpd,www}
chown -R mysql:mysql var/run/mysqld

Start services

Restart lighttpd and mysql (MariaDB)
service mysql start
service lighttpd restart

Congratulations!

You have made the bare minimum needed to get lighttpd and PHP5 to work in a chroot.
On to the issues

Issues

lighttpd cannot make outgoing connections or has no internet connection

WordPress throws a rather vague error. Owncloud was a bit more descriptive, saying that the server has no internet connection even when it is clearly accessible from the outside internet (firewall issues aside).
A common issue chrooted environments have is that there is no internet connection. Usually it is caused by a missing resolv.conf in chrooted /etc and solved by either making one or copying one over. But in the howto, this was already done. Similar to a missing resolv.conf, it turns out that lighttpd (or PHP?) still cannot resolve DNS because there is a lib that left out and was not copied over, but in no way l2chroot’s fault.

Fix
cp -Rp /lib/x86_64-linux-gnu/libnss_{dns,files}* /lightyroot/lib/x86_64-linux-gnu/
Note that libnss_{dns,files}.so.2 may be a symlink.

From here
Aside: it’s frustrating to see people ask in a forum, then say that they’ve fixed it in the next post, but never gave the solution. Just like that thread. At least someone else cared and posted the solution.

“Error establishing database connection”

Unfortunately, this error is rather vague and causes can start from a dead mysql service to missing things. In this case, this is either a permission issue or lighttpd can’t find mysql.sock within the chroot environment.
If this is a permission issue, most likely mysqld cannot create a socket file. If so, try
chown -R mysql:mysql /lightyroot/var/run/mysqld

Failing that, lighttpd cannot find that socket file within the chroot. To fix, we will edit /etc/mysql/my.cnf and relocate mysqld.sock to be located inside lighttpd’s chroot.
Change all instances of
socket = /var/run/mysqld/mysqld.sock (or wherever that was set to)
to
socket = /lightyroot/var/run/mysqld/mysqld.sock

then edit /etc/mysql/debian.cnf with the same changes.

Alternatively, bind mounts can be used if you don’t want to bother with config files. Make sure this runs every time the server boots.
mount -o bind /var/run/mysqld /lightyroot/var/run/mysqld

Missing locales

Owncloud was being dodgy with this error. It says that it cannot find locales en_US.UTF8, and others.
True enough, it cannot find those locales because it is not located inside the chroot, which is also why dpkg-reconfigure locale did not work for this.

cp -Rpv /usr/share/{zoneinfo,locale} /lightyroot/usr/share
cp -Rpv /usr/lib/locale /lightyroot/usr/lib
should fix it.

l2chroot

#!/bin/bash
# Use this script to copy shared (libs) files to Apache/Lighttpd chrooted
# jail server.
# ----------------------------------------------------------------------------
# Written by nixCraft <http://www.cyberciti.biz/tips/>
# (c) 2006 nixCraft under GNU GPL v2.0+
# + Added ld-linux support
# + Added error checking support
# ------------------------------------------------------------------------------
# See url for usage:
# http://www.cyberciti.biz/tips/howto-setup-lighttpd-php-mysql-chrooted-jail.html
# -------------------------------------------------------------------------------
# Set CHROOT directory name
BASE="/webroot"

if [ $# -eq 0 ]; then
echo "Syntax : $0 /path/to/executable"
echo "Example: $0 /usr/bin/php5-cgi"
exit 1
fi

[ ! -d $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
do
d="$(dirname $i)"
[ ! -d $BASE$d ] && mkdir -p $BASE$d || :
/bin/cp $i $BASE$d
done

# 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 ];
then
echo "Copying $sldl $BASE$sldlsubdir..."
/bin/cp $sldl $BASE$sldlsubdir
else
:
fi

Usage notes:
Save this somewhere as l2chroot and do chmod +x l2chroot
Change BASE="/webroot" to wherever lighttpd’s chroot is located. In this howto, /lightyroot was used.
Code by NixCraft

Advertisements

Carefully twist your words.

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

WordPress.com Logo

You are commenting using your WordPress.com 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