Как я nginx ставил и вместе с apache и Cpanel работать заставил
Итак, задача - поставить nginx, что бы он работал в качестве фронтэнд-прокси и разгружал apache от медленных коннектов.
Цель - nginx обрабатывает все запросы, при этом он перенаправляет запросы apache и позволяет не висеть по долгу тяжелым процессам apache, даже если клиент медленный, поскольку мгновенно забирает ответ apache и отдает его клиенту уже из собственного буфера.
Задача осложняется тем, что сделать это нужно на сервере с панелью управления Cpanel, которая генерирует httpd.conf каждый раз при изменениях на сервере (например, при добавлении сабдомена в панели) и совершенно ничего не знает о конфиге nginx.
Можно повесить apache на 81 порт, например, а nginx на 80 и дальше проксировать все запросы от nginx апачу, но тогда придется научить Cpanel генерировать httpd.conf с настройкой на 81 порт. Это не сложно - достаточно поправить темплайт виртуалхоста Cpanel, но есть риск потери совместимости, поэтому я избрал другой путь - более универсальный и менее рискованный.
Итак, поехали:
Допустим apache уже установлен и настроен. Если это не так - установите и настройте, это не тема данной статьи.
Апач есть.
Ставим nginx:
Офсайт:
http://sysoev.ru
Качаем отсюда:
http://sysoev.ru/nginx/download.html
Вперед:
cd /usr/local/src wget http://sysoev.ru/nginx/nginx-0.6.32.tar.gz tar -zxvf nginx-0.6.32.tar.gz cd nginx-0.6.32 ./configure --prefix=/usr/local/nginx --without-http_charset_module --without-http_ssi_module --without-http_userid_module --without-http_access_module --without-http_auth_basic_module --without-http_empty_gif_module --without-http_gzip_module --without-http_rewrite_module --without-pcre make make install
nginx поставили.
Теперь конфигурируем nginx:
Чаще всего конфиг находится тут:
/usr/local/nginx/conf/nginx.conf
ну в любом случае найдете.
Допустим IP вашего сервера 123.456.654.321
Тогда примерно так:
worker_processes 3;
events {
worker_connections 1024;
use epoll; # типа быстрее других
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
reset_timedout_connection on; # не все клиенты умеют закрывать соединения...
client_body_buffer_size 256k;
client_max_body_size 5m;
proxy_buffer_size 32k;
large_client_header_buffers 8 32k;
server {
listen 89.149.254.12:85;
access_log off;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://123.456.654.321:80;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
Этого конфига в принципе достаточно. Заметьте - мы повесили nginx на 85-ый порт, apache мы оставляем на 80-ом, это позволит сохранить максимальную совместимость в самых разных, нестандартных ситуациях.
Стартуем nginx:
/usr/local/nginx/sbin/nginx
Проверяем:
telnet 123.456.654.321 85
Если соединяется и не пишет, что connectiob refused - значит nginx нормально запустился и слушает 85-ый порт.
Теперь, с помощью iptables перенаправляем трафик с 80 порта нашего IP на 85, т.е. перенаправляем трафик на nginx, откуда он уже будет отдавать его apache на 80 порт.
iptables -t nat -A PREROUTING -p tcp -m tcp -d 123.456.654.321 --dport 80 -j DNAT --to-destination 123.456.654.321:85
Для этого необходимо иметь iptables и поддержку NAT в нем.
После этого, желательно сохранить конфигурацию iptables, что бы при рестартах данное перенаправление не терялось:
iptables-save > /etc/sysconfig/iptables
Внимание, если на сервере установлен apf то вместо того, что бы выполнять эту команду в терминале, открываем файл /etc/apf/preroute.rules и вбиваем эту строчку туда, после чего рестартуем apf apf -r
Осталось установить модуль апача mod_rpaf:
Качать отсюда:
http://man-linux.ru/ext/aHR0cDovL3N0ZGVyci5uZXQvYXBhY2hlL3JwYWYvZG93bmxvYWQv/
Поехали:
cd /usr/local/src wget http://stderr.net/apache/rpaf/download/mod_rpaf-0.6.tar.gz tar -zxvf mod_rpaf-0.6.tar.gz cd mod_rpaf-0.6 apxs -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c
После этого модуль должен появиться в директории модулей apache, например тут:
/usr/lib/httpd/modules/mod_rpaf-2.0.so
Остается прописать включение этого модуля в конфиге apache:
LoadModule rpaf_module modules/mod_rpaf-2.0.so RPAFenable On RPAFsethostname On RPAFproxy_ips 123.456.654.321
Если несколько IP - их можно вбивать в строке RPAFproxy_ips через пробел.
Это можно сделать прямо в httpd.conf, но я для этого создал файл /etc/httpd/conf.d/rpaf-2.0.conf и прописал в нем. На серверах с Cpanel, возможно понадобится прописывать в другом файле, поскольку Cpanel сама генерит httpd.conf из собственных темплейтов, но в ее httpd.conf есть include несколько файлов конфигов по умолчанию.
Ну и напоследок, полезная инфа:
Управление nginx:
Управлять nginx можно с помощью сигналов. Номер главного процесса по умолчанию записывается в файл /usr/local/nginx/logs/nginx.pid. Изменить имя этого файла можно при конфигурации сборки или же в nginx.conf директивой pid. Главный процесс поддерживает следующие сигналы:
TERM, INT - быстрое завершение
QUIT - плавное завершение
HUP - изменение конфигурации, обновление изменившейся временной зоны (только для FreeBSD и Linux), запуск новых рабочих процессов с новой конфигурацией, плавное завершение старых рабочих процессов
USR1 - переоткрытие лог-файлов
USR2 - обновление исполняемого файла
WINCH - плавное завершение рабочих процессов
Управлять рабочими процессами по отдельности не нужно. Тем не менее, они тоже поддерживают некоторые сигналы:
TERM, INT - быстрое завершение
QUIT - плавное завершение
USR1 - переоткрытие лог-файлов
Например, команда для перезапуска nginx может выглядеть так:
kill -HUP `cat /usr/local/etc/nginx/logs/nginx.pid`
Что еще. Для мониторинга nginx написал скрипт, который проверяет его состояние и если нужно перезапускает, а так же может высылать уведомление админу. Cкрипт конечно не идеальный, сделан топориком на коленке, но работает:
#!/bin/bash email='mail@mail.ru' if [[ -e /usr/local/nginx/logs/nginx.pid ]] then pid=`cat /usr/local/nginx/logs/nginx.pid` hn=`hostname` if [[ $1 ]] then if [[ $1 == 'start' ]] then /usr/local/nginx/sbin/nginx echo 'nginx started' fi if [[ $1 == 'restart' ]] then kill -HUP $pid echo 'nginx restarted' fi if [[ $1 == 'stop' ]] then kill -QUIT $pid echo 'nginx stoped' fi else if ! ps $pid > /dev/null > /dev/null; then /usr/local/nginx/sbin/nginx > /dev/null # echo "nginx on $hn was DOWN, restarted " `date` | mail -s 'nginx down' $email else echo 'nginx UP and have PID:' echo $pid fi fi else /usr/local/nginx/sbin/nginx > /dev/null #echo "nginx on $hn was DOWN, restarted " `date` | mail -s 'nginx down' $email fi
Обратите внимание на пути - возможно их придется подредактировать. Если надо, что бы скрипт отсылал емайлы при падениях nginx - нужно расскомментировать две строчки (32 и 40) а также, в начале скрипта указать нужный email, ну и команда mail должна в системе поддерживаться.
Если скрипт вызвать без параметров - он проверяет состояние nginx и в случае необходимости запускает его.
Так же поддерживаются параметры start|stop|restart выполняющие соответсвующие действия.
Достаточно поставить скрипт без параметров на крон, например раз в три минуты - он будет раз в три минуты проверять состояние nginx и в случае необходимости запустит его.
Удачи!
В конфиге nginxа, сдается мне неверно указан ip в директивах
listen, proxy_pass
Комментарий от Anton Shevtsov — 19 Август 2009 @ 9:43
Насколько я понимаю, это решение будет работать если нет виртуальных name-based хостов у апача, ведь их тоже надо описаывать в конфиге ngnix?
Комментарий от Anton Shevtsov — 26 Август 2009 @ 13:36
Вообще что-то странное получается. Если nginx слушает на 85 порту ip1, мы роутим на него трафик приходящий на ip1:80, а nginx дальше обращается к ip1:80, то мы получаем кольцо? как быть?
Комментарий от ivanko — 11 Сентябрь 2009 @ 12:56
> В конфиге nginxа, сдается мне неверно указан ip в директивах
> listen, proxy_pass
Да, при редактировани статьи остался IP с одного из моих серверов, поправил :)
> Насколько я понимаю, это решение будет работать если нет виртуальных name-based хостов у апача, ведь > их тоже надо описаывать в конфиге ngnix?
В том то и дело, что nginx работает ровно как прокси и ничего иного для сайтов висящих на данном конкретном IP описывать не надо - апач отдает nginx’у, он уже отдает клиенту.
> Вообще что-то странное получается. Если nginx слушает на 85 порту ip1, мы роутим на него трафик приходящий на ip1:80, а nginx дальше обращается к ip1:80, то мы получаем кольцо? как быть
Кольца не получается, поскольку запрос на 80 порт идущий из “вне” с помощью iptables переадресуется прямиком на nginx (85 порт), тот же в свою очередь запрашивает данные уже локально с того же 80 порта и поскольку данные запрашиваются локально iptables не переадресует их - кольца не получается и схема отлично работает.
Комментарий от admin — 21 Сентябрь 2009 @ 21:05