Isolated Nginx & PHP installation script

This script install a chrooted nginx and php environment on a specific folder of the system. Is has been developped and tested on Debian Squeeze 64 bits. It requires that the nginx, php5-cgi, spawn-fcgi packages are installed. In addition, if you want mysql support, install php5-mysql before launching the script.

If you need help, want to report bug or submit improvements, please post a comment at the bottom of the page.

#! /bin/bash
set -e

#### 
# Isolated Nginx & PHP Installation script
# Julien Vehent - 20110418
# http://wiki.linuxwall.info
# Distributed under GPL V2 licence
####


# The main container. change it to match your configuration.
chroot_container=/var/www/


# this function copies shared libraries from a binary to the chroot
# stolen from nixcraft and then improved a bit ;)
libs_to_chroot(){
        local d="$1"            # JAIL ROOT
        local pFILE="$2"        # copy bin file libs
        local files=""
        local _cp="/bin/cp"

        # get rid of blanks and (0x00007fff0117f000)
        files="$(ldd $pFILE |  awk '{ print $3 }' | sed -e '/^$/d' -e '/(*)$/d')"

        for i in $files
        do
            dcc="${i%/*}" # get dirname only
            [ ! -d ${d}${dcc} ] && mkdir -p ${d}${dcc} # create missing dirs
            [ ! -e ${d}${dcc}${i} ] && ${_cp} -f $i ${d}${dcc} # copy missing only

            # recursively get shared libraries of shared library
            libs_to_chroot "${d}" "${i}"
        done

        # Works with 32 and 64 bit ld-linux
        sldl="$(ldd $pFILE | grep 'ld-linux' | awk '{ print $1}')"
        sldlsubdir="${sldl%/*}"
        #[ ! -f ${d}${sldl} ] && ${_cp} -f ${sldl} ${d}${sldlsubdir}
        if [ ! -f ${d}${sldl} ];
        then
                ${_cp} -f ${sldl} ${d}${sldlsubdir}
        fi
}

install_env() {
	local target="$1"

	mkdir -p $chroot_container$target/{etc/init.d,dev,var/log/nginx,var/run,var/www,var/tmp,var/lib/nginx,usr/sbin,usr/bin,usr/share,bin,sbin,tmp,lib/lsb,lib64,usr/lib}
	chmod 1777 $chroot_container$target/var/tmp/
	mknod -m 0666 $chroot_container$target/dev/null c 1 3
	mknod -m 0666 $chroot_container$target/dev/random c 1 8
	mknod -m 0666 $chroot_container$target/dev/urandom c 1 9
	mknod -m 0666 $chroot_container$target/dev/zero c 1 5

	# create a user and a group that have the same name as target
	groupadd $target
	useradd -d $chroot_container$target/var/www -g $target -M -N -s /bin/false $target

	# copy startup program
	#cp -f /sbin/start-stop-daemon $chroot_container$target/sbin/
	#cp -f /lib/lsb/init-functions $chroot_container$target/lib/lsb/

    # copy ln to recreate symbolic links inside the chroot
    cp -f /bin/ln $chroot_container$target/bin/
}

install_nginx(){
	local target="$1"
	local nginx_bin=`which nginx`
	cp -f $nginx_bin $chroot_container$target$nginx_bin
	cp -fr /etc/nginx $chroot_container$target/etc/
	#copy shared libs to target
	libs_to_chroot "${chroot_container}${target}" "${nginx_bin}"

	cp -f /lib/libnss_compat.so.2 $chroot_container$target/lib/
	cp -f /lib/libnsl.so.1 $chroot_container$target/lib/
	cp -f /lib/libnss_nis.so.2 $chroot_container$target/lib/
	cp -f /lib/libnss_files.so.2 $chroot_container$target/lib/

	cp -fr /etc/{nsswitch.conf,services,hosts*,localtime,protocols,ld.so.cache,ld.so.conf,ld.so.conf.d,host.conf} $chroot_container$target/etc/

	#we just give the chroot the user it needs, that is root and its own
	head -n 1 /etc/passwd > $chroot_container$target/etc/passwd
	tail -n 1 /etc/passwd >> $chroot_container$target/etc/passwd

	head -n 1 /etc/group > $chroot_container$target/etc/group
	tail -n 1 /etc/group >> $chroot_container$target/etc/group
	
	

	# change user ownership
	chown -R $target:$target $chroot_container$target/var/www/

	
	# install basic configuration
	echo "user $target $target;
worker_processes  1;
error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       /etc/nginx/mime.types;
    access_log    /var/log/nginx/access.log;
    sendfile        on;
    keepalive_timeout  65;
    tcp_nodelay        on;
    gzip  on;
    gzip_disable \"MSIE [1-6]\.(?!.*SV1)\";
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}
" > $chroot_container$target/etc/nginx/nginx.conf

	# install basic virtual host
	echo "Nginx can be configured to accept requests from 127.0.0.1 only (coming from a proxy or load balancer)"
	echo -n "Do you want to allow 127.0.0.1 only and deny all (can be changed in site config) ? y/n > "
	read response
	
	if [ $response == "y" ]
	then
		echo "server {
    listen  127.0.0.1:$nginxport;"> $chroot_container$target/etc/nginx/sites-available/default
	else
		echo "server {
    listen  $nginxport;"> $chroot_container$target/etc/nginx/sites-available/default
	fi

        echo "
    server_name  $fqdn;
    access_log  /var/log/nginx/$fqdn.access.log;
    root   /var/www;
    index  index.cgi index.php index.html index.htm;">>$chroot_container$target/etc/nginx/sites-available/default

	
    if [ $phpsupport -eq 1 ]
    then
        echo "
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass   127.0.0.1:$phpport;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  \$document_root\$fastcgi_script_name;
    }">> $chroot_container$target/etc/nginx/sites-available/default
    fi

    if [ $fcgiwrapsupport -eq 1 ]
    then
        echo "
    location ~ \.cgi {
        include fastcgi_params;
        fastcgi_pass    unix:/var/run/fcgiwrap.sock;
        fastcgi_index   index.cgi;
        fastcgi_param  SCRIPT_FILENAME  \$document_root\$fastcgi_script_name;
    }">>$chroot_container$target/etc/nginx/sites-available/default
    fi

	echo "
}" >> $chroot_container$target/etc/nginx/sites-available/default

	# test the setup
	chroot $chroot_container$target/ $nginx_bin -t

	echo "nginx setup finished."
}



install_php(){

    aptitude install php5-cgi spawn-fcgi

    local spawnfcgibin=`which spawn-fcgi`
	local php_bin=`which php5-cgi`

    if [ ! -x $chroot_container$target$spawnfcgibin ]
    then
        cp -f $spawnfcgibin $chroot_container$target$spawnfcgibin
        libs_to_chroot "${chroot_container}${target}" "$spawnfcgibin"
    fi

	cp -f $php_bin $chroot_container$target$php_bin
	cp -fr /etc/php5 $chroot_container$target/etc/
	cp -fr /usr/lib/php5 $chroot_container$target/usr/lib/
	cp -fr /usr/share/zoneinfo $chroot_container$target/usr/share/

	libs_to_chroot "${chroot_container}${target}" "${php_bin}"

	echo "php setup finished."
}

install_mysql(){

	aptitude update 1>/dev/null
	aptitude install php5-mysql

	cp -fr /etc/php5 $chroot_container$target/etc/
	cp -fr /usr/lib/php5 $chroot_container$target/usr/lib/

	local mysql_lib=`find /usr/lib/php5/ -iname mysql.so`
	libs_to_chroot "${chroot_container}${target}" "${mysql_lib}"

	find /lib -iname libgcc_s.so* -exec cp -f {} $chroot_container$target/lib/ \;

	echo "php5-mysql setup finished."
}

install_fcgiwrap(){
	aptitude update 1>/dev/null
	aptitude install fcgiwrap spawn-fcgi

    fcgiwrap_bin=`which fcgiwrap`
	cp -f $fcgiwrap_bin $chroot_container$target$fcgiwrap_bin
	libs_to_chroot "${chroot_container}${target}" "${fcgiwrap_bin}"
    
    spawnfcgibin=`which spawn-fcgi`
    if [ ! -x $chroot_container$target$spawnfcgibin ]
    then
        cp -f $spawnfcgibin $chroot_container$target$spawnfcgibin
        libs_to_chroot "${chroot_container}${target}" "$spawnfcgibin"
    fi
}

install_perl(){
	local perl_bin=`which perl`
    #copy perl binary
	cp -f $perl_bin $chroot_container$target$perl_bin

    echo "copying all included perl modules from @INC, be patient (~5/10min)"
    for INC in $(perl -e 'foreach(@INC){print "$_\n";}')
    do
        if [ "$INC" != "." ]
        then
            if [ -h "$INC" ]
            then
                DESTLINK=$(readlink -f $INC)
                mkdir -p $chroot_container$target$DESTLINK
                cp -fr $DESTLINK/* $chroot_container$target$DESTLINK/
                chroot $chroot_container$target ln -s $DESTLINK $INC
            else
                if [ -d "$INC" ]
                then
                    mkdir -p $chroot_container$target$INC
                    cp -fr $INC $chroot_container$target$INC
                    for perl_lib in $(find $INC -iname '*.so' -exec ls {} \;)
                    do
                        libs_to_chroot "${chroot_container}${target}" "${perl_lib}"
                    done
                fi
            fi
        fi
    done

    #copy dynamic libs
	libs_to_chroot "${chroot_container}${target}" "${perl_bin}"

	echo "perl setup finished."
}

install_mojolicious(){
    # install chroot env, then move there and issue mojolicious install
    cp $(which bash) ${chroot_container}${target}$(which bash)
    libs_to_chroot "${chroot_container}${target}" $(which bash)

    cp $(which env) ${chroot_container}${target}$(which env)
    libs_to_chroot "${chroot_container}${target}" $(which env)

    cp $(which curl) ${chroot_container}${target}$(which curl)
    libs_to_chroot "${chroot_container}${target}" $(which curl)

    curl -s -L cpanmin.us | perl - Mojolicious --local-lib=/tmp-${target}-mojolicious/
    cp -r /tmp/${target}-mojolicious/lib/perl5/* ${chroot_container}${target}/usr/lib/perl5/
    cp -r /tmp/${target}-mojolicious/bin/*  ${chroot_container}${target}/usr/bin/
    rm -rf /tmp/${target}-mojolicious/

    echo "mojolicious setup finished."
}


create_supervised_config(){

	aptitude update 1>/dev/null
	aptitude install daemontools daemontools-run

    mkdir -p /etc/sv/spawn-fcgi-$target
    echo "#! /bin/bash
CHROOTBIN=/usr/sbin/chroot
CHROOTPATH=$chroot_container$target
SPAWNBIN=`which spawn-fcgi`
PHP5BIN=`which php5-cgi`
PHP5PORT=$phpport
PHP5ADDR=127.0.0.1
USER=$target
exec \$CHROOTBIN \$CHROOTPATH \$SPAWNBIN -n -a \$PHP5ADDR -p \$PHP5PORT -u \$USER -g \$USER -C 3 \$PHP5BIN
" > /etc/sv/spawn-fcgi-$target/run

	chmod +x /etc/sv/spawn-fcgi-$target/run
	update-service --add /etc/sv/spawn-fcgi-$target spawn-fcgi-$target
}

create_control(){
	echo "#! /bin/sh
#
### BEGIN INIT INFO
# Provides:          control-$target
# Required-Start:    $syslog
# Required-Stop:     $syslog
# Should-Start:      $local_fs
# Should-Stop:       $local_fs
# Default-Start:     2
# Default-Stop:      0 1 6
# Short-Description: starts/stops $target
# Description:       starts and stops $target
#                    a webserver chroot for $fqdn
#
### END INIT INFO

CHROOTBIN=/usr/sbin/chroot
CHROOTPATH=$chroot_container$target
NGINXDAEMON=`which nginx`
NAME=nginx

PHP5SUPPORT=$phpsupport
SPAWNBIN=`which spawn-fcgi`
PHP5BIN=`which php5-cgi`
PHP5PORT=$phpport
PHP5ADDR=127.0.0.1
PHPSUPERVISE=$phpsupervise

FCGIWRAPSUPPORT=$fcgiwrapsupport
FCGIWRAPSOCK=/var/run/fcgiwrap.sock
FCGIWRAPBIN=`which fcgiwrap`

USER=$target

DESC='chroot webserver (nginx/php) for $fqdn'
set -e
. /lib/lsb/init-functions
test_nginx_config() {
  if \$CHROOTBIN \$CHROOTPATH -t \$NGINXDAEMON_OPTS >/dev/null 2>&1
  then
    return 0
  else
    \$CHROOTBIN \$CHROOTPATH \$NGINXDAEMON -t \$NGINXDAEMON_OPTS
    return \$?
  fi
}
case \"\$1\" in
  start)
        echo \"Starting \$DESC ---\"

	# launching nginx
        test_nginx_config
        start-stop-daemon --chroot \$CHROOTPATH --start --pidfile /var/run/nginx.pid \
                --exec \$NGINXDAEMON -- \$NGINXDAEMON_OPTS || true
        echo -n \"nginx started with pid \"; cat \$CHROOTPATH/var/run/nginx.pid ; echo

        if [ \$PHP5SUPPORT -eq 1 ]
        then
            if [ \$PHPSUPERVISE -eq 1 ]
            then
                svc -u /etc/service/spawn-fcgi-$target
                echo \"spawn-fcgi and php5 started under supervise\"
            else
                start-stop-daemon --chroot \$CHROOTPATH --start \
                    --exec \$SPAWNBIN -- -a \$PHP5ADDR -p \$PHP5PORT \
                    -u \$USER -g \$USER -P /var/run/php5-cgi.pid \$PHP5BIN || true

            	echo -n \"php5-cgi started with pid \"; cat \$CHROOTPATH/var/run/php5-cgi.pid ; echo
            fi
        fi

        if [ \$FCGIWRAPSUPPORT -eq 1 ]
        then
            start-stop-daemon --chroot \$CHROOTPATH --start \
                    --exec \$SPAWNBIN -- -s \$FCGIWRAPSOCK \
                    -u \$USER -g \$USER -P /var/run/fcgiwrap.pid \$FCGIWRAPBIN || true

        	echo -n \"fcgiwrap started with pid \"; cat \$CHROOTPATH/var/run/fcgiwrap.pid ; echo
        fi

        ;;
  stop)
        echo \"Stopping \$DESC ---\"
	if [ -e \$CHROOTPATH/var/run/nginx.pid ]
	then
		kill \`cat \$CHROOTPATH/var/run/nginx.pid\`
		if [ \$? -ne 0 ]
		then
			echo  -n \"couldn't kill nginx - found running pid \" ; \`cat \$CHROOTPATH/var/run/nginx.pid\`;echo
		else
                	echo \"stopping nginx\"
		fi
        else
                echo \"nginx is not running, no pid file in /var/run/\"
        fi

        if [ \$PHP5SUPPORT -eq 1 ]
        then
            if [ \$PHPSUPERVISE -eq 1 ]
            then
                svc -d /etc/service/spawn-fcgi-$target
                echo \"spawn-fcgi and php5 stopped under supervise\"
            else
                if [ -e \$CHROOTPATH/var/run/php5-cgi.pid ]
                then
                    ps -p \`cat \$CHROOTPATH/var/run/php5-cgi.pid\` 2>&1 1>/dev/null
                    if [ $? -ne 0 ]
                    then
                        echo \"php5-cgi process not running\"
                    else
                        kill \`cat \$CHROOTPATH/var/run/php5-cgi.pid\`
                		if [ \$? -ne 0 ]
                		then
		    	            echo  -n \"couldn't kill php5-cgi - pid=\";\`cat \$CHROOTPATH/var/run/php5-cgi.pid\`;echo
                		else
                        	echo \"php5-cgi has been stopped\"
            		    fi
                    fi
                else
                    echo \"no php5-cgi pid file in /var/run/\"
                fi
            fi
        fi

        if [ \$FCGIWRAPSUPPORT -eq 1 ]
        then
            if [ -e \$CHROOTPATH/var/run/fcgiwrap.pid ]
            then
                ps -p \`cat \$CHROOTPATH/var/run/fcgiwrap.pid\` 2>&1 1>/dev/null
                if [ $? -ne 0 ]
                then
                    echo \"fcgiwrap process not running\"
                else
                    kill \`cat \$CHROOTPATH/var/run/fcgiwrap.pid\`
                	if [ $? -ne 0 ]
                	then
		    	        echo  -n \"couldn't kill fcgiwrap - pid=\";\`cat \$CHROOTPATH/var/run/fcgiwrap.pid\`;echo
                	else
                       	echo \"fcgiwrap has been stopped\"
            		fi
                fi
            else
                echo \"no fcgiwrap.pid file in /var/run/\"
            fi
        fi
            
        ;;
  restart)
        echo -n \"Restarting \$DESC: \"
	\$0 stop
        sleep 1
	\$0 start
        ;;
  configtest)
        echo -n \"Testing \$DESC configuration: \"
        if test_nginx_config
        then
          echo \"\$NAME.\"
        else
          exit \$?
        fi
        ;;
  status)
        status_of_proc -p \$CHROOTPATH/var/run/nginx.pid \"\$NGINXDAEMON\" nginx && exit 0 || exit $?
    " >> /etc/init.d/control-$target

if [ $phpsupport -eq 1 ]
then
    echo "
        status_of_proc -p \$CHROOTPATH/var/run/php5-cgi.pid \"\$PHP5BIN\" php5-cgi && exit 0 || exit $?
    " >> /etc/init.d/control-$target
fi

    echo "
        ;;
  *)
        echo \"Usage: \$0 {start|stop|restart|status|configtest}\" >&2
        exit 1
        ;;
esac
exit 0

" >> /etc/init.d/control-$target

	if [ -e /etc/init.d/control-$target ]
	then
		chmod +x /etc/init.d/control-$target
	else
		echo "couldn't create control file /etc/init.d/control-$target"
		exit 1
	fi
}

usage(){
	echo "Chroot installation script"
	echo "Syntax: $0 <site name>"
    echo "example: $0 chroot-example"
    echo "this will initiate the creation of $chroot_container/chroot-example"
	exit 1
}

[ $# -ne 1 ] && usage
[ $UID -ne 0 ] && echo "You need to be root to launch this program" && usage

target=$1
[ -d $chroot_container$target ] && echo "Target already exist !" && exit 1

echo -n "This is going to install a chroot environment in $chroot_container$target. Do you want to continue ? y/n > "
read response
if [ $response != "y" ]
then
	exit 1
fi

# create the environment
install_env "${target}"

# get some information from the administrator before we start
port_available=$(netstat -taupen|grep :50|grep LISTEN|awk '{print $4}'|cut -d : -f 2|sort|tail -n 1)
port_available=$(( $port_available + 1 ))

echo -n "Nginx listening port ($port_available seems available) ? > "
read nginxport

echo -n "What will the FQDN of the server be ? (example.com) ? > "
read fqdn

echo -n "Do you want chrooted php support ? y/n > "
read response
if [ $response == "y" ]
then
    phpsupport=1
	echo -n "Which port should php cgi listen on ? > "
	read phpport


	echo -n "Would you like to install php5-mysql support in the chroot ? y/n > "
	read response
	if [ $response == "y" ]
	then
		install_mysql "${target}"
	fi
else
    phpsupport=0
fi


if [ $phpsupport -eq 1 ]
then
	install_php "${target}"

	echo -n "Would you like to add to supervise php using daemon-tools 'supervise' ? y/n > "
	read response
	if [ $response == "y" ]
	then
        phpsupervise=1
		create_supervised_config "${target}"
	else
        phpsupervise=0
	fi
fi


echo -n "Do you want chrooted fcgiwrap support ? y/n > "
read response
if [ $response == "y" ]
then
    fcgiwrapsupport=1
	install_fcgiwrap "${target}"
else
    fcgiwrapsupport=0
fi

echo -n "Do you want perl support ? y/n > "
read response
if [ $response == "y" ]
then
	install_perl "${target}"
    echo -n "Also want Mojolicious ? y/n > "
    read response
    if [ $response == "y" ]
    then
        install_mojolicious "${target}"
    fi
fi

# call installation functions
install_nginx "${target}"
create_control "${target}"

echo -n "Would you like to add this server to startup runlevel 2 ? y/n > "
read response
if [ $response == "y" ]
then
	SAVEPWD=`pwd`
	cd /etc/rc2.d
	ln -s ../init.d/control-$target S17control-$target
	cd /etc/rc6.d
	ln -s ../init.d/control-$target K01control-$target
	cd $SAVEPWD
fi

echo -n "Would you like to create a logrotate rule for this server ? y/n > "
read response
if [ $response == "y" ]
then
	echo "$chroot_container$target/var/log/nginx/*.log {
        daily
        missingok
        rotate 7
        compress
        delaycompress
        notifempty
        create 640 root adm
        sharedscripts
        postrotate
                [ ! -f $chroot_container$target/var/run/nginx.pid ] || kill -USR1 \`cat $chroot_container$target/var/run/nginx.pid\`
        endscript
}" > /etc/logrotate.d/$target
fi

echo "The installation of the chroot environment is finished."
echo "To control the environement, use the script located at /etc/init.d/control-$target (outside the chroot)"

exit 0


Discussion

, 2011/03/19 05:59

Works fine but I receive an error that makes little sense.

cp: missing destination file operand after `/var/www/xxxxxxx'

This happens after it says there has been a successful installation, I tried looking through the script for some sort of error but I could find none.

I'm using Debian Lenny 6.0 x64

, 2011/06/19 20:24

doesn't work, after 'do you want to install perl y/n' it errors:

cp: missing destination file operand after `/var/www/xxxxxxx' (xxx being whatever name you gave it)

then doesn't finish install. tested on squeeze

, 2011/06/19 21:09

derr.. ran it as root everything works until:

Nginx can be configured to accept requests from 127.0.0.1 only (coming from a proxy or load balancer) Do you want to allow 127.0.0.1 only and deny all (can be changed in site config) ? y/n > n Chroot installation script Syntax: /usr/sbin/chroot <site name> example: /usr/sbin/chroot chroot-example this will initiate the creation of /var/wwwchroot-example then dies to shell prompt. ??

, 2011/06/21 14:21

interesting, can you copy the full log, including the command line arguments please

, 2012/08/19 19:23

Hold on a second, YOU are teilnlg ME to wake up???? You better stop drinking the fluoridated kool aid. Yes, race is an important issue, but you obviously dont understand WHY it is. If the jew wipes out white people first, exactly who will they be blending in with at that point? DOH! They cant wipe out their only means of cover. The reason race is important is because its used to divide you and keep you quarreling amongst yourselves. The reason they flood so-called white countries with Arabs is because they know white people will see that as a bigger threat than the jew. So, you waste all your energy trying to fight the wrong opponent. Now that your countries are full of people of different races, you cant see the forest for the trees.

, 2012/08/20 06:01

This was a great program, but one cnlomaipt was there was an implication that the mass home ownership that began in the 30s was a major factor in the crisis. The home finance system worked fine (for several decades) until the wave of deregulation of banking and growth of the unregulated shadow banking sector occurred. The large investment banks were allowed to use our money to make their risky bets. Not just in housing securities, but in hedge funds and other risky vehicles. We took most of the risk they took most of the profits. All in the name of removing burdensome government. Had sensible regulations been in place, this mess could not have occurred.

Enter your comment
If you can't read the letters on the image, download this .wav file to get them read to you.
 
en/ressources/articles/script_chroot_nginx.txt · Last modified: 2011/04/19 00:28 by julien
CC Attribution-Noncommercial-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0