В статье рассматривает пример размещение HTTP сервера nginx в chroot окружение. В данном примере nginx используется исключительно как front-end к апачу. Настройка связки nginx+fast-cgi+[чего-то-там-ещё] в чруте не рассматривается.
Для начала - немного общей инфы.
nginx (engine x) (читается как Энджайн икс) — веб-сервер и почтовый прокси-сервер, работающий на Unix-подобных операционных системах (тестировалась сборка и работа на FreeBSD, OpenBSD, Linux, Solaris, Mac OS X). nginx — это очень быстрый HTTP сервер, который часто используют вместо или совместно с Apache, чтобы снизить нагрузку на сервер и увеличить скорость обработки запросов посетителей.
В большинстве случаев, nginx используется как front-end и ставится ДО апача, проксируя пользовательские запросы. nginx можно настроить на отдачу статического контента (видео, графика, мультимедиа и т.д.), тем самым снизив нагрузку на апач.
Что такое chroot?
chroot — операция изменения корневого каталога в Unix-подобных операционных системах. Программа, запущенная с изменённым корневым каталогом, будет иметь доступ только к файлам, содержащимся в данном каталоге. Программа, корень которой был перенесён в другой каталог, не может обращаться к файлам вне этого каталога. Это обеспечивает удобный способ помещения в «sandbox» («песочницу») тестовой, ненадёжной или любой другой потенциально опасной программы.
Для чего всё это надо?
Единственный вменяемый аргумент - chroot даст немного безопасности и позволит малость разгрузить сервер.
Что нам понадобится
- Как ни странно - линуховый дистриб :) Я буду показывать на примере Debian Lenny
- Несколько пакетов, включая сам chroot
- Исходники nginx. Их можно скачать с сайта автора
Для начала установим deb-овский пакет chroot-а
# apt-get install schroot
Для проверки зависимостей нам также понадобятся ldd и strace
# apt-get install strace # cd /usr/local/src # wget http://sysoev.ru/nginx/nginx-0.8.22.tar.gz # tar xzfv nginx-0.8.22.tar.gz # cd nginx-0.8.22
Перед сборкой нгинкса советую посмотреть выхлоп ./configure --help и определить для себя нужные параметры сборки. В данном примере будет показан самый простой вариант без особых изысков.
# ./configure --user=nobody --group=nogroup --with-http_ssl_module --with-http_realip_module / --with-http_addition_module --error-log-path=/var/log/nginx/error.log / --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid
Если будут сыпаться ошибки нехватки каких-то библиотек, типа PCRE, установите их (apt-get install libpcre3-dev) и повторите configure. Затем стандартно
# make # make install
Не забываем, что make install делается от рута. На выхлопе будет что-то типа такого
cp conf/koi-utf '/usr/local/nginx/conf' cp conf/win-utf '/usr/local/nginx/conf' test -f '/usr/local/nginx/conf/mime.types' || cp conf/mime.types '/usr/local/nginx/conf' cp conf/mime.types '/usr/local/nginx/conf/mime.types.default' test -f '/usr/local/nginx/conf/fastcgi_params' || cp conf/fastcgi_params '/usr/local/nginx/conf' cp conf/fastcgi_params '/usr/local/nginx/conf/fastcgi_params.default' test -f '/usr/local/nginx/conf/nginx.conf' || cp conf/nginx.conf '/usr/local/nginx/conf/nginx.conf' cp conf/nginx.conf '/usr/local/nginx/conf/nginx.conf.default' test -d '/usr/local/nginx/logs' || mkdir -p '/usr/local/nginx/logs' test -d '/usr/local/nginx/logs' || mkdir -p '/usr/local/nginx/logs' test -d '/usr/local/nginx/html' || cp -r html '/usr/local/nginx' test -d '/usr/local/nginx/logs' || mkdir -p '/usr/local/nginx/logs' make[1]: Leaving directory `/usr/local/src/nginx-0.8.22'
Если не задавали префиксов, по умолчанию всё установилось в /usr/local/nginx/ Проверим работоспособность
# cd /usr/local/nginx/sbin # ./nginx # ps ax|grep nginx
Должно получиться примерно следующее
20544 ? Ss 0:00 nginx: master process ./nginx 20545 ? S 0:00 nginx: worker process 20764 pts/2 S+ 0:00 grep nginx
Если всё выглядит подобным образом - нгинкс установлен нормально. Чтобы прибить его, достаточно кильнуть мастер процесс
# kill 20544
Весь nginx со всеми конфигами, логами и пр. лежит в /usr/local/nginx/
Приступим к помещению nginx-а в chroot окружение.
Для начала посмотрим, какие библиотеки необходимы ему для работы
# ldd /usr/local/nginx/sbin/nginx linux-gate.so.1 => (0xb7eee000) libcrypt.so.1 => /lib/i686/cmov/libcrypt.so.1 (0xb7ea2000) libpcre.so.3 => /usr/lib/libpcre.so.3 (0xb7e79000) libssl.so.0.9.8 => /usr/lib/i686/cmov/libssl.so.0.9.8 (0xb7e31000) libcrypto.so.0.9.8 => /usr/lib/i686/cmov/libcrypto.so.0.9.8 (0xb7cde000) libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7cda000) libz.so.1 => /usr/lib/libz.so.1 (0xb7cc5000) libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7b6a000) /lib/ld-linux.so.2 (0xb7eef000)
Выхлоп - нужные нам библиотеки. Создадим chroot каталог, в котором будет запущен nginx. Также создадим катологи для библиотек, список которых получили выше (пути берём их этого же выхлопа libssl.so.0.9.8 => /usr/lib/i686/cmov/libssl.so.0.9.8)
# mkdir /chroot/web/nginx/usr/lib/i686/cmov -p # mkdir /chroot/web/nginx/lib/i686/cmov -p # mkdir /chroot/web/nginx/var/log/nginx -p # mkdir /chroot/web/nginx/var/run -p # mkdir /chroot/web/nginx/etc -p # mkdir /chroot/web/nginx/local -p # mkdir /chroot/web/nginx/dev -p # mkdir /chroot/web/nginx/usr/lib/ssl -p
Скопируем nginx и библиотеки в свежесозданные каталог
# mv /usr/local/nginx /chroot/web/nginx/usr/local/ # cp /lib/i686/cmov/libcrypt.so.1 /chroot/web/nginx/lib/i686/cmov/libcrypt.so.1 # cp /usr/lib/libpcre.so.3 /chroot/web/nginx/usr/lib/libpcre.so.3 # cp /usr/lib/i686/cmov/libssl.so.0.9.8 /chroot/web/nginx/usr/lib/i686/cmov/libssl.so.0.9.8 # cp /usr/lib/i686/cmov/libcrypto.so.0.9.8 /chroot/web/nginx/usr/lib/i686/cmov/libcrypto.so.0.9.8 # cp /lib/i686/cmov/libdl.so.2 /chroot/web/nginx/lib/i686/cmov/libdl.so.2 # cp /usr/lib/libz.so.1 /chroot/web/nginx/usr/lib/libz.so.1 # cp /lib/i686/cmov/libc.so.6 /chroot/web/nginx/lib/i686/cmov/libc.so.6 # cp /lib/ld-linux.so.2 /chroot/web/nginx/lib/ld-linux.so.2
После того, как определили, какие либы нужны nginx-у, надо "на всякий пожарный" посмотреть зависимости уже скопированых библиотек. При необходимости, скопировать их (зависимости) в /chroot/web/nginx/
# ldd /lib/i686/cmov/libcrypt.so.1
linux-gate.so.1 => (0xb7fcb000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7e24000)
/lib/ld-linux.so.2 (0xb7fcc000)
# ldd /usr/lib/i686/cmov/libssl.so.0.9.8
linux-gate.so.1 => (0xb7f50000)
libcrypto.so.0.9.8 => /usr/lib/i686/cmov/libcrypto.so.0.9.8 (0xb7d9c000)
libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7d98000)
libz.so.1 => /usr/lib/libz.so.1 (0xb7d82000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7c27000)
/lib/ld-linux.so.2 (0xb7f51000)
# ldd /usr/lib/i686/cmov/libcrypto.so.0.9.8
linux-gate.so.1 => (0xb7f7f000)
libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7e0e000)
libz.so.1 => /usr/lib/libz.so.1 (0xb7df9000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7c9d000)
/lib/ld-linux.so.2 (0xb7f80000)
# ldd /lib/i686/cmov/libdl.so.2
linux-gate.so.1 => (0xb7faa000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7e31000)
/lib/ld-linux.so.2 (0xb7fab000)
# ldd /usr/lib/libz.so.1
linux-gate.so.1 => (0xb7f27000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7d9d000)
/lib/ld-linux.so.2 (0xb7f28000)
# ldd /lib/i686/cmov/libc.so.6
/lib/ld-linux.so.2 (0xb7dd0000)
linux-gate.so.1 => (0xb7dcf000)
# ldd /lib/ld-linux.so.2
statically linked
Судя по всему, из библиотек больше ничего не понадобится. Теперь определим, какие файлы открываются nginx-ом при работе
# strace -o /opt/nginx-files /usr/local/nginx/sbin/nginx
# cat /opt/nginx-files|grep open
open("/etc/ld.so.cache", O_RDONLY) = 3
open("/lib/i686/cmov/libcrypt.so.1", O_RDONLY) = 3
open("/usr/lib/libpcre.so.3", O_RDONLY) = 3
open("/usr/lib/i686/cmov/libssl.so.0.9.8", O_RDONLY) = 3
open("/usr/lib/i686/cmov/libcrypto.so.0.9.8", O_RDONLY) = 3
open("/lib/i686/cmov/libdl.so.2", O_RDONLY) = 3
open("/usr/lib/libz.so.1", O_RDONLY) = 3
open("/lib/i686/cmov/libc.so.6", O_RDONLY) = 3
open("/etc/localtime", O_RDONLY) = 3
open("/usr/local/nginx/logs/error.log", O_WRONLY|O_CREAT|O_APPEND|O_LARGEFILE, 0644) = 3
open("/usr/lib/ssl/openssl.cnf", O_RDONLY|O_LARGEFILE) = 4
open("/usr/local/nginx/conf/nginx.conf", O_RDONLY|O_LARGEFILE) = 4
open("/usr/local/nginx/conf/mime.types", O_RDONLY|O_LARGEFILE) = 5
open("/etc/nsswitch.conf", O_RDONLY) = 4
open("/etc/ld.so.cache", O_RDONLY) = 4
open("/lib/i686/cmov/libnss_compat.so.2", O_RDONLY) = 4
open("/lib/i686/cmov/libnsl.so.1", O_RDONLY) = 4
open("/etc/ld.so.cache", O_RDONLY) = 4
open("/lib/i686/cmov/libnss_nis.so.2", O_RDONLY) = 4
open("/lib/i686/cmov/libnss_files.so.2", O_RDONLY) = 4
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 4
open("/etc/group", O_RDONLY|O_CLOEXEC) = 4
open("/usr/local/nginx/logs/access.log", O_WRONLY|O_CREAT|O_APPEND|O_LARGEFILE, 0644) = 4
open("/usr/local/nginx/logs/error.log", O_WRONLY|O_CREAT|O_APPEND|O_LARGEFILE, 0644) = 5
#rm /opt/nginx-files
Из вышеуведенного понятно, какие ещё библиотеки необходимо скопировать в chroot для работы nginx-а. Соответсвенно, копируем эти библиотеки.
# cp /etc/ld.so.cache /chroot/web/nginx/etc/ld.so.cache # cp /lib/i686/cmov/libcrypt.so.1 /chroot/web/nginx/lib/i686/cmov/libcrypt.so.1 # cp /usr/lib/libpcre.so.3 /chroot/web/nginx/usr/lib/libpcre.so.3 # cp /usr/lib/i686/cmov/libssl.so.0.9.8 /chroot/web/nginx/usr/lib/i686/cmov/libssl.so.0.9.8 # cp /usr/lib/i686/cmov/libcrypto.so.0.9.8 /chroot/web/nginx/usr/lib/i686/cmov/libcrypto.so.0.9.8 # cp /lib/i686/cmov/libdl.so.2 /chroot/web/nginx/lib/i686/cmov/libdl.so.2 # cp /usr/lib/libz.so.1 /chroot/web/nginx/usr/lib/libz.so.1 # cp /lib/i686/cmov/libc.so.6 /chroot/web/nginx/lib/i686/cmov/libc.so.6 # cp /etc/localtime /chroot/web/nginx/etc/localtime # cp /usr/lib/ssl/openssl.cnf /chroot/web/nginx/usr/lib/ssl/openssl.cnf # cp /etc/nsswitch.conf /chroot/web/nginx/etc/nsswitch.conf # cp /lib/i686/cmov/libnss_compat.so.2 /chroot/web/nginx/lib/i686/cmov/libnss_compat.so.2 # cp /lib/i686/cmov/libnsl.so.1 /chroot/web/nginx/lib/i686/cmov/libnsl.so.1 # cp /lib/i686/cmov/libnss_nis.so.2 /chroot/web/nginx/lib/i686/cmov/libnss_nis.so.2 # cp /lib/i686/cmov/libnss_files.so.2 /chroot/web/nginx/lib/i686/cmov/libnss_files.so.2 # cp /etc/passwd /chroot/web/nginx/etc/passwd # cp /etc/group /chroot/web/nginx/etc/group # cp /etc/hosts /chroot/web/nginx/etc/hosts # cp /etc/resolv.conf /chroot/web/nginx/etc/resolv.conf
Из /chroot/web/nginx/etc/passwd удалите все строки оставив только пользователя nobody в /chroot/web/nginx/etc/group оставьте только nogroup
# cat /chroot/web/nginx/etc/passwd nobody:x:65534:65534:nobody:/nonexistent:/bin/sh # cat /chroot/web/nginx/etc/group nogroup:x:65534:
Создадим /dev/null, он необходим для нгинкса
# ls -l /dev/null crw-rw-rw- 1 root root 1, 3 Ноя 7 2009 /dev/null
Обратим внимание на две волшебных цифири и буковку crw-rw-rw- root root 1, 3 Ноя 7 2009 /dev/null Создадим /dev/null в чруте
# mknod /chroot/web/nginx/dev/null c 1 3 # chmod 666 /chroot/web/nginx/dev/null
Установим владельца на нгинкс в чруте (правильней было бы устанавливать не на всё подряд, но т.к. статья идёт только для примера - сделаем "по-быстрому")
# chown -R nobody.nogroup /chroot/web/nginx
Пробуем запустить nginx в чруте
# chroot /chroot/web/nginx/ /usr/local/nginx/sbin/nginx # ps ax|grep ngin 19335 ? Ss 0:00 nginx: master process /usr/local/nginx/sbin/nginx 19336 ? S 0:00 nginx: worker process 19509 pts/2 S+ 0:00 grep ngin
Чтобы проверить, заходим броузером на http://localhost/ Если увидим следующую картинку - нгинкс завёлся

Смотрим
# ls -l /chroot/web/nginx/var/run/ итого 4 -rw-r--r-- 1 root root 6 Ноя 7 03:21 nginx.pid # cat /chroot/web/nginx/var/run/nginx.pid 19335 # ps ax|grep nginx 19335 ? Ss 0:00 nginx: master process /usr/local/nginx/sbin/nginx 19336 ? S 0:00 nginx: worker process 21039 pts/2 S+ 0:00 grep nginx
Далее - пишем скрипт автозапуска, суть которого сводится к запуску нгинкса в чруте /usr/sbin/chroot /chroot/web/nginx/ /usr/local/nginx/sbin/nginx
Раскидываем линки на этот скрипт в /etc/rc1.d - rc6.d
Настройки nginx-а лежат в /chroot/web/nginx/usr/local/nginx/conf/nginx.conf На сайте разработчика всё пркрасно документировано, причём на русском языке, поэтому в данной статье тонкости конфигурирования сервера не рассматриваются. Для проброса http на апач, в общих чертах делается следующее:
1) В настройках апача правим /etc/apache2/ports.conf
Listen 1234 NameVirtualHost *:1234
2) В конфигах сайтов в /etc/apache2/sites-enabled/
<VirtualHost *:1234>
3) В /chroot/web/ngin/usr/local/nginx/conf/nginx.conf добавляем следующую секцию (обратите внимание, на proxy_pass http://127.0.0.1:1234/)
server {
listen aaa.bbb.ccc.ddd:80; # ip вашего сервера и порт
server_name server.my www.server.my; # Имя вашего домена с www и без
location / { # another virtual host using mix of IP-, name-, and port-based configuration
proxy_pass http://127.0.0.1:1234/; # перенаправляем запросы на локалхост и порт 1234
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
4) Iptables-ом открываем порт 80, но при этом НЕ открываем 1234
Вроде всё. Буду рад любой конструктивной критике.


Поясните пожалуйста смысл
Поясните пожалуйста смысл данных действий. Насколько я понял, если вам через уязвимость web приложения загрузят на web сервер какой нибудь php шелл, то этот шелл будет обрабатыватся apache и иметь доступ ко всему.
Смысл в том, что NGINX более
Смысл в том, что NGINX более шустро отдаёт контент + до кучи кеширует запросы. В результате разгружается апач в бэк энде. В плане безопасности - никто не застрахован от кривых php скриптов. В плане защиты может помочь mod_security + snort. NGINX же суётся в чрут - чтобы при его взломе, кульхацкер за пределы песочницы не вылез.
Спасибо за статью! Все
Спасибо за статью! Все работает. Было бы здорово все-таки раскрыть еще тему с: "правильней было бы устанавливать не на всё подряд, но т.к. статья идёт только для примера - сделаем "по-быстрому")"
А чё тут раскрывать-то? chown
А чё тут раскрывать-то?
chown -R nobody.nogroup /chroot/web/nginx/var/log/nginx
chown -R nobody.nogroup /chroot/web/nginx/var/run/
А как сделать?
Есть сервер на котором стоит nginx как фронтэнд для apache, он отдает статику, а индеец лопатит скрипты.
Сервант я немного перенастроил, чтобы апач запускался от каждого пользователя отдельно и чтобы они не видели соседние папаки.
Собственно вопрос:
Как сделать чтобы нджинкс заглядывал за статикой в каждую папку, но при этом не мог заглядывыть в соседнюю? Т.к. апач у каждого пользователя запускается с правами user: user1 groupe: user1, добавлять всех пользователей в группу www-data чтобы нджинкс мог шарить по папкам не очень хочется, но приемлемого решения я пока не нашел... А оставлять индейца на сервере в одниночестве что-то не хочется...
Не совсем понял фразу "Как
Не совсем понял фразу "Как сделать чтобы нджинкс заглядывал за статикой в каждую папку, но при этом не мог заглядывыть в соседнюю?" Если он заглядывает во ВСЕ папки, то по логике получается, что эти папки "соседние". Или я как-то не так понимаю. Давай поподробнее.
Дополнение
Собственно вопрос: Как запускать nginx от имени пользователей вертуальных хостов?
Я вот несовсем понял
Я вот несовсем понял сакральный смысл запускать кучу апачей от имён разных пользователей. Зачем это? Не проще ли ОДИН апач также в чрут посадить, прикрутить к нему mod_security + mod_evasive и запускать от www-data? А чтобы скрипты по соседним папкам не шастали - в конфиге каждого сайта пропиши
<IfModule mod_php5.c> php_admin_value open_basedir "/var/www/[bla-bla-bla]:/[bla-bla-bla]/[bla-bla-bla]/[bla-bla-bla]:/[bla-bla-bla]" </IfModule>Где вместо [bla-bla-bla] поставь имена папок, куда разрешен доступ.
Вопрос был не тот
Вопрос был не в том, зачем запускать кучу апачей, а в том, как запустить nginx от имени виртуального пользователя, а индеец был тут исключительно для примера...
Не совсем понял, что именно
Не совсем понял, что именно ты хотел, но может Chrootuid тебе поможет?
До Штирлица не дошло письмо из центра...
Прочитал еще раз-все равно не дошло..... ;)
Еще раз
Задача-для массового хостинга необходимо запускать apache от имени разных пользователей, это решается с помощью сборки apache-mpm -сделано это для того, чтобы пользователи и скрипты не могли шарить по домашним директориям других пользователей (соседей по серверу) для экономии ресурсов на 80й порт вешается Nginx который отдает графику и другие статические файлы, а скрипты проксирует apache, индеец лопатит только скрипты, после обработки скрипта, соединение между nginx и apache разрывается благодаря чему сохраняются ресурсы и дочерние процессы индейца не висят в памяти, nginx в этом плане, менее требователен к ресурсам и тихо отдает данные, даже медленным клиентам, не расходуя много ресурсов.
Чтобы Nginx мог отдавать статику-он должен иметь права на доступ в корневые директории виртуальных хостов-так? ТАК!
Но каждая директория обслуживается под своим пользователем-я вижу 2 варианта развития событий:
1) всех пользователей от имени которых запускается apache напрмер: test1 test2 test3, загоняем в одну группу например: webserver, сервер nginx, который по умолчанию, работает от имени пользователя www-data тоже добавляем в группу webserver и разрешаем этой группе чтение из домашних директорий пользователей чтобы он имел право только на чтение статических данных, естественно выпиливаем у пользователя www-data доступ к шеллу. Так реализовано сейчас!
2) Виртуальные хосты apache запускаются от имени разных пользователей test1 test2 test3-c этим все понятно, как сделать так чтобы виртуальные хосты nginx запускались также от имен пользователей test1 test2 test3?
Первая схема работает нормально и без сбоев, но что-то как-то сыкотно....
schroot
Для чего нужно ставить пакет schroot ?
# which chroot
/usr/sbin/chroot
# dpkg -S /usr/sbin/chroot
coreutils: /usr/sbin/chroot
Доступ nginx к виртуальным хостам
Делаем nginx'у своего пользователя, чтобы не предоставить скриптам, запускаемым в mpm апача лишний доступ, например www-static, и добавляем его к каждому пользователю в группу (не наоборот). После этого можно ставить на директории права 660 и всё прекрасно работает.
Отправить комментарий