Практический пример: Apache
Наверное, один из наиболее часто помещаемых в CE сервисов - веб-сервер Apache. Про это много написано и под разными углами, но я все же рискну повториться. Рассмотрим пошагово перенос в CE программной связки Apache 1.3.x + PHP 5 с учетом взаимодействия с СУБД MySQL (классический комплекс, именуемый в народе "LAMP" - Linux + Apache + MySQL + PHP). В примере предполагается, что мы имеем дело с дистрибутивной сборкой Apache в Slackware (для вашей системы файлы могут быть расположены немного по-другому, но принцип должен быть понятен).
Вот скрипт для автоматизированного создания CE: #!/bin/sh # create chrooted environment for Apache 1.3 + PHP 5 # Den aka Diesel <diesel@sherdart.net>
PREFIX=/chroot/httpd APACHE_PREFIX=/usr PHP_PREFIX=/usr APACHE_DATADIR=/var/www
# создаем структуру каталогов:
mkdir -p $PREFIX mkdir -p $PREFIX/dev mkdir -p $PREFIX/etc mkdir -p $PREFIX/lib mkdir -p $PREFIX/tmp mkdir -p $PREFIX/var/cache/proxy mkdir -p $PREFIX/var/run mkdir -p $PREFIX/$APACHE_PREFIX/bin mkdir -p $PREFIX/$APACHE_PREFIX/lib mkdir -p $PREFIX/$APACHE_PREFIX/sbin mkdir -p $PREFIX/$APACHE_PREFIX/libexec mkdir -p $PREFIX/var/log/apache mkdir -p $PREFIX/var/run/mysql mkdir -p $PREFIX/$PHP_PREFIX/lib/php mkdir -p $PREFIX/home
# выставляем 'sticky bit' на /tmp:
chmod 1777 $PREFIX/tmp
# создаем файл устройства /dev/null:
mknod $PREFIX/dev/null c 1 3 chmod 666 $PREFIX/dev/null chown root:sys $PREFIX/dev/null
# копируем конфигурационные файлы:
cat /etc/group|egrep "apache:|nobody:|nogroup:" > $PREFIX/etc/group cat /etc/passwd|egrep "apache:|nobody:" > $PREFIX/etc/passwd cat /etc/shadow|egrep "apache:|nobody:" > $PREFIX/etc/shadow chmod 640 $PREFIX/etc/shadow cp /etc/HOSTNAME $PREFIX/etc cp /etc/host.conf $PREFIX/etc cp /etc/hosts $PREFIX/etc cp /etc/nsswitch.conf $PREFIX/etc cp /etc/resolv.conf $PREFIX/etc cp /etc/localtime $PREFIX/etc cp -R /etc/apache $PREFIX/etc
# копируем данные и лог-файлы:
cp -R $APACHE_DATADIR $PREFIX`dirname $APACHE_DATADIR` cp -R /var/log/apache $PREFIX/var/log
# копируем бинарные файлы:
cp $APACHE_PREFIX/bin/htdigest $PREFIX/$APACHE_PREFIX/bin cp $APACHE_PREFIX/bin/mm-config $PREFIX/$APACHE_PREFIX/bin cp $APACHE_PREFIX/bin/htpasswd $PREFIX/$APACHE_PREFIX/bin cp $APACHE_PREFIX/bin/checkgid $PREFIX/$APACHE_PREFIX/bin cp $APACHE_PREFIX/bin/dbmmanage $PREFIX/$APACHE_PREFIX/bin cp $APACHE_PREFIX/sbin/ab $PREFIX/$APACHE_PREFIX/sbin cp $APACHE_PREFIX/sbin/apxs $PREFIX/$APACHE_PREFIX/sbin cp $APACHE_PREFIX/sbin/httpd $PREFIX/$APACHE_PREFIX/sbin cp $APACHE_PREFIX/sbin/logresolve $PREFIX/$APACHE_PREFIX/sbin cp $APACHE_PREFIX/sbin/rotatelogs $PREFIX/$APACHE_PREFIX/sbin cp $APACHE_PREFIX/sbin/apachectl-standard $PREFIX/$APACHE_PREFIX/sbin cp $APACHE_PREFIX/sbin/apacheconfig $PREFIX/$APACHE_PREFIX/sbin cp -R $APACHE_PREFIX/libexec/apache $PREFIX/$APACHE_PREFIX/libexec
# копируем библиотеки:
for BINARY in "$APACHE_PREFIX/sbin/httpd $APACHE_PREFIX/libexec/apache/libphp5.so $APACHE_PREFIX/lib/php/extensions/mysql.so"; do for i in `ldd $BINARY|awk '{print $3}'`; do d=$(dirname $i) if [[ $d != .* ]]; then mkdir -p $PREFIX$d; fi if [[ $d != .* ]]; then cp $i $PREFIX$d; fi done done cp -d /lib/libnss_compat* $PREFIX/lib cp -d /lib/libnss_dns* $PREFIX/lib cp -d /lib/ld-* $PREFIX/lib cp -d /lib/libnsl* $PREFIX/lib cp -R -d /usr/lib/gconv $PREFIX/usr/lib cp -R $PHP_PREFIX/lib/php $PREFIX/$PHP_PREFIX/lib cp -d -R /usr/lib/locale/en_GB $PREFIX/usr/lib/locale cp -d -R /usr/lib/locale/en_GB.utf8 $PREFIX/usr/lib/locale cp -d -R /usr/lib/locale/ru_RU $PREFIX/usr/lib/locale cp -d -R /usr/lib/locale/ru_RU.koi8r $PREFIX/usr/lib/locale cp -d -R /usr/lib/locale/ru_RU.utf8 $PREFIX/usr/lib/locale
Обратите внимание на несколько моментов:
- из /etc/passwd мы взяли только записи про apache, nobody, nogroup (не стоит подвергать информацию о других учетных записях опасности быть украденой при взломе этого конкретного сервиса, исключение составляет только ситуация с использованием ~/public_html/)
- не забывайте про /etc/localtime, если хотите, чтобы сервис жил с вами в одной временной зоне
- по-минимуму можно было не копировать все бинарные файлы Apache, а обойтись только httpd
- обвязка ldd в этом скрипте сделана на скорую руку (однако работает в подавляющем большинстве случаев) - имя какой-нибудь библиотеки, нестандартно выведенной, может не захватиться в переменную
- не забывайте про /etc/nsswitch.conf и resolv.conf при помещении в CE сетевых сервисов
- также не забывайте про библиотеки libnss, libnss_dns и libnsl
- при желании уменьшить объем, занимаемый библиотеками и исполняемыми бинарными файлами - после копирования и тестирования работоспособности CE сделайте им strip
- файлы из /usr/lib/gconv и /usr/lib/locale нужны для корректной работы с локалями, отличными от английской (C) - без этих файлов, например, русские буквы не будут восприниматься как корректные символы алфавита, что может сказаться на работе регулярных выражений в PHP
- некоторым сервисам может требоваться не только файл устройства /dev/null, но и /dev/random вместе с /dev/urandom (например, для того же BIND - иначе у него не работают корректно функции шифрования)
- если вам для работы каких-нибудь CGI-скриптов необходим PERL, его так же необходимо поместить в CE, не забыв про /usr/lib/perl5
- учтите, что если вы не предпримете никаких дополнительных мер, PHP функция mail() не будет работать в CE, т.к. она пытается вызвать бинарный файл SMTP-клиента, который отсутствует в CE (в интернете описаны методы обхода этого с использованием модулей из репозитария PEAR)
- не пренебрегайте возможностью установить (с помощью утилиты chattr) флаг иммунитета к изменениям (immutable) для важных файлов, которые не должны меняться в ходе работы - например, для конфигурационных файлов
Возможно, есть еще какие-то тонкости, однако я в своей практике с ними не сталкивался, и поэтому написать ничего про них не могу. Помещение MySQL в CE производится аналогично, никаких особых подводных камней там нет, помимо уже описанных.