Nginx в качестве проксирующего сервера Apache

В предыдущей статье, "Веб сервер Nginx, обзор функциональных возможностей", речь шла об основных функциональных возможностях сервера Nginx, а так-же затронут вопрос его использования в качестве проксирующего фронтенд-сервера в связке с веб сервером Apache. Здесь хотелось-бы рассказать о практической стороне вопроса, то есть перейти непосредственно к установке и настройке вышеупомянутой связки, Nginx - Apache. Так как всем остальным *nix системам, я предпочитаю FreeBSD, на ней и будем все это поднимать.

Итак, имеем операционную систему FreeBSD 7.1 STABLE платформа amd64, с установленным веб сервером Apache/2.2.9. Общая схема работы, то есть взаимодействия, клиент - Nginx - Apache, будет выглядеть следующим образом:

схема связки веб серверов nginx - apache

В операционной системе FreeBSD, стандартным способом установки приложений, является система портов, поэтому не будем изобретать велосипед с исходниками ( хотя иногда конечно может и это понадобиться ), а воспользуемся портами, во первых это удобней, во-вторых установка по-умолчанию, подходит для большинства ситуаций, ну и в третьих, при установке из портов, приложение автоматически попадает в базу данных установленных пакетов /var/db/pkg, и в последствии доступно для таких программ как pkg_info и portupgrade.

Установка веб сервера Nginx из портов FreeBSD

vds-admin /# cd /usr/ports Переходим в каталог портов
vds-admin /usr/ports# make search name=nginx Ищем нужный порт
Port: nginx-0.7.61 Стабильная версия сервера Nginx
Path: /usr/ports/www/nginx
Info: Robust and small WWW server
Maint: osa@FreeBSD.org
B-deps: pcre-7.9
R-deps: pcre-7.9
WWW: http://sysoev.ru/nginx/

Port: nginx-devel-0.8.4 Версия для разработки
Path: /usr/ports/www/nginx-devel
Info: Robust and small WWW server
Maint: osa@FreeBSD.org
B-deps: pcre-7.9
R-deps: pcre-7.9
WWW: http://sysoev.ru/nginx/
vds-admin /usr/ports# cd www/nginx Ставить будем стабильную версию, туда и идем
vds-admin /usr/portswww/nginx# make install clean

После запуска утилиты make на экран лезет довольно внушительный список дополнительных модулей, которые можно включить или выключить. Никакой экзотики нам в данном случае не нужно, я все оставил по-умолчанию. Честно говоря я не пользуюсь данными опциями а предпочитаю запускать скрипт configure, он предоставляет возможность более гибкой настройки параметров сборки и установки, например, выбор директории для установки, расположение конфигурационных файлов, лог файлов, бинарников, и прочее. Итак, вот весь список предлагаемых опций с краткими описаниями.

[ ] DEBUG                     Режим отладки. Полезно на стадии тестирования и отладки конфигурации
[ ] IPV6                      Поддержка протокола IP 6-й версии
[ ] GOOGLE_PERFTOOLS          Включить поддержку google-perftools
[X] HTTP_MODULE               Включение функций HTTP сервера
[ ] HTTP_ACCESSKEY_MODULE     Модуль для генерации защищенных ссылок
[ ] HTTP_ADDITION_MODULE      Фильтр, добавляющий текст до и после ответа
[ ] HTTP_DAV_MODULE           Модуль для поддержки WebDAV методов PUT, DELETE, MKCOL, COPY и MOVE
[ ] HTTP_EVAL_MODULE          Разбирает ответ проксируемого сервера или memcached сервера на переменные
[ ] HTTP_FANCYINDEX_MODULE    Модуль позволяющий строить листинг файлов с добавлением стилей
[ ] HTTP_FLV_MODULE           Модуль для стриминга флэш-видео в формате flv
[ ] HTTP_GZIP_STATIC_MODULE   Модуль для отдачи клиенту предварительно сжатого файла с тем-же именем но с расширением  ".gz".
[ ] HTTP_MOGILEFS_MODULE      Поддержка файловой системы mogilefs.
[ ] HTTP_PERL_MODULE          Встроенный Perl.
[ ] HTTP_RANDOM_INDEX_MODULE  Модуль, выдает в качестве индексного файла, случайный файл из каталога.
[ ] HTTP_REALIP_MODULE        Модуль для замены адреса клиента в заголовке.
[ ] HTTP_RESPONSE_MODULE      Модуль для отдачи произвольного текста, прописанного в директивы модуля.
[X] HTTP_REWRITE_MODULE       Модуль для изменения URI с помощью регулярных выражений, выдачи редиректов и выбора конфигурации в зависимости от переменных.
[ ] HTTP_SECURE_LINK_MODULE   Модуль для проверки правильности запрошенной ссылки.
[ ] HTTP_SSL_MODULE           Модуль поддержки SSL.
[X] HTTP_STATUS_MODULE        Модуль, показывающий информационную страницу о текущем статусе Nginx.
[ ] HTTP_SUB_MODULE           Модуль для замены в ответе, одной строки, на другую.
[ ] HTTP_UPLOAD_MODULE        Модуль для аплоадов multipart/form-data.
[ ] HTTP_UPLOAD_PROGRESS      В силу особенностей реализации nginx, без данного модуля не получится организовать показ статуса загрузки файлов.
[ ] HTTP_UPSTREAM_FAIR        Модуль для балансировки нагрузки. Отправляет входящие запросы на наименее загруженный бакэнд.
[ ] HTTP_UPSTREAM_KEEPALIVE   Поддержка keepalive- соединений с бакэндами, в том числе memcached.
[ ] HTTP_XSLT_MODULE          XSLT фильтр.
[ ] HTTP_ZIP_MODULE           Модуль для создания zip архивов "на лету".
[ ] MAIL_MODULE               Модуль для работы nGinx в качестве почтового прокси сервера.
[ ] MAIL_IMAP_MODULE          Модуль IMAP4 прокси.
[ ] MAIL_POP3_MODULE          Модуль POP3 прокси.
[ ] MAIL_SMTP_MODULE          Модуль SMTP прокси.
[ ] MAIL_SSL_MODULE           Модуль для поддержки SSL/TLS для POP3/IMAP/SMTP.
[ ] PASSENGER_MODULE          Аналог апачевского mod_rails ( Phusion Passenge ).
[X] WWW                       Стандартный набор HTML файлов для проверки.

После нажатия [ Ok ], начинается процесс конфигурирования, сборки и установки веб сервера Nginx. По окончанию, проверяем, что и как у нас установилось:

vds-admin /usr/ports/www/nginx# rehash Перечитать пути к исполняемым файлам.
vds-admin /usr/ports/www/nginx# nginx -v Версия Nginx.
nginx version: nginx/0.7.61
vds-admin /usr/ports/www/nginx# nginx -V Параметры с которыми был установлен Nginx.
nginx version: nginx/0.7.61
configure arguments: --prefix=/usr/local/etc/nginx --with-cc-opt='-I /usr/local/include' --with-ld-opt='-L /usr/local/lib' --conf-path=/usr/local/etc/nginx/nginx.conf --sbin-path=/usr/local/sbin/nginx --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx-error.log --user=www --group=www --http-client-body-temp-path=/var/tmp/nginx/client_body_temp --http-proxy-temp-path=/var/tmp/nginx/proxy_temp --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi_temp --http-log-path=/var/log/nginx-access.log --with-http_stub_status_module --with-pcre

Настройка сервера Nginx в качестве reverse-proxy сервера

Итак, веб сервер Nginx установлен. Всю интересующую информацию по расположению директорий и файлов Nginx, выдает вышеприведенная команда, nginx -V.

Рабочая директория располагается в /usr/local/etc/nginx ( если при запуске configure, не указано иное ), там-же находится главный конфигурационный файл /usr/local/etc/nginx/nginx.conf, бинарный файл nginx, расположен по пути, /usr/local/sbin/nginx ( опять-же если указано иное ). Директории, client_body_temp, proxy_temp, fastcgi_temp, являются служебными и предназначены для хранения временных файлов различными модулями сервера Nginx. Кроме того, были установлены пользователь и группа от имени которых будут запускаться рабочие процессы, по-умолчанию это www.

Теперь нужно пересадить сервер Apache на другой адрес или порт. Здесь есть несколько вариантов, все зависит от конкретной ситуации. Например у вас один внешний IP адрес, именно на нем, на 80-м порту, должен слушать Nginx и принимать входящие HTTP соединения, соответственно Apache там быть не должно, его можно посадить на локальный адрес 127.0.0.1, порт может быть любой, например, тоже 80, внешние соединения все равно не попадут на него, либо можно оставить Apache на том-же адресе, но назначить порт, отличный от 80, например 8080, либо, если есть такая необходимость, сделать и то и другое.

Правим конфигурационные файлы Apache. Сначала изменим адрес или порт на котором Apache принимает соединения, файл httpd.conf, находим директиву Listen и устанавливаем следующее значение:

  1. Listen 127.0.0.1:80             Мы оставим именно это значение, что-бы не устраивать путаницу.

Как было сказано ранее, в зависимости от вашей ситуации, можно поставить и так:

  1. listen внешний_IP_адрес:8080

или так:

  1. Listen 12345

Все приведенные значения одинаково рабочие.

Если вы планируете обслуживать несколько виртуальных хостов, придется подправить соответствующий файл конфигурации, в Apache2, это /extra/httpd-vhosts.conf:

  1. NameVirtualHost *:80
  2.     ServerAdmin webmaster@nginxhost
  3.     DocumentRoot "/usr/home/nginxhost/public_html"
  4.     ServerName nginxhost
  5.     ServerAlias nginxhost
  6.     ErrorLog "/var/log/nginxhost"
  7.     CustomLog "/var/log/nginxhost_custom" common

Не забываем перезапустить Apache. Для этого можно использовать и стартовый скрипт в /usr/local/etc/rc.d, но мне привычней так:

vds-admin /# /usr/local/sbin/apachectl configtest
Syntax OK
vds-admin /# /usr/local/sbin/apachectl graceful

Смотрим что у нас показывает netstat -Lan:

vds-admin /# netstat -Lan
Current listen queue sizes (qlen/incqlen/maxqlen)
Proto Listen Local Address
tcp4 0/0/128 127.0.0.1.80 Вот наш Apache
.......................
.......................

Вроде все работает, но есть один нюанс, сервер Apache не будет видеть реальные IP адреса клиентов, для него все запросы будут приходить с адреса 127.0.0.1, его он и будет писать в свои лог файлы. Естественно это неправильно. Что-бы исправить ситуацию, необходимо установить для Apache, дополнительный модуль, mod_fpaf, а из Nginx передавать дополнительные заголовки, устанавливая их специальными директивами конфигурационного файла. Этим сейчас и займемся.

vds-admin /usr/ports# make search name=mod_rpaf Ищем в портах необходимый модуль.
v Port: mod_rpaf-0.6 Этот нам не интересен, он для Apache 1.3
Path: /usr/ports/www/mod_rpaf
Info: Make proxied requests appear with client IP
Maint: apache@FreeBSD.org
B-deps: apache-1.3.41_1 expat-2.0.1 perl-5.8.9_3
R-deps: apache-1.3.41_1 expat-2.0.1 perl-5.8.9_3
WWW: http://stderr.net/apache/rpaf/

Port: mod_rpaf-ap2-0.6 Этот мы и будем ставить
Path: /usr/ports/www/mod_rpaf2
Info: Make proxied requests appear with client IP
Maint: apache@FreeBSD.org
B-deps: apache-2.0.63_3 expat-2.0.1 libiconv-1.13 perl-5.8.9_3
R-deps: apache-2.0.63_3 expat-2.0.1 libiconv-1.13 perl-5.8.9_3
WWW: http://stderr.net/apache/rpaf/

vds-admin /usr/ports# cd www/mod_rpaf2
vds-admin /usr/ports/www/mod_rpaf2# make install clean

Установка длится меньше минуты. Когда все закончится, снова идем в файл конфигурации Apache, httpd.conf. При установке mod_rpaf в конфигурационный файл, должна была добавиться следующая строка:

  1. LoadModule rpaf_module        libexec/apache22/mod_rpaf.so После установки, строка закомментирована.

Раскомментируйте строку загрузки модуля, если нужно mod_rpaf, а ниже допишите следующие строки, это такой мини-конфиг модуля:

  1. RPAFenable On
  2. RPAFsethostname On
  3. RPAFproxy_ips 127.0.0.1
  4. RPAFheader X-Forwarded-For

Проверяем конфигурационный файл на предмет синтаксических ошибок и перезагружаем Apache. С ним вроде закончили.

vds-admin /# /usr/local/sbin/apachectl configtest
Syntax OK
vds-admin /# /usr/local/sbin/apachectl graceful
Я использую вышеприведенный вариант по привычке, мне так удобней, вы можете сделать все это с помощью стартового скрипта из /usr/local/etc/rc.d

Теперь перейдем к Nginx. Настроим минимальную рабочую конфигурацию, при которой все запросы будут уходить на Apache, кроме картинок.

user  www;                      #Имя пользователя, под которым запускаются рабочие процессы сервера Nginx.
worker_processes  1;            #Количество рабочих процессов Nginx.
error_log  logs/error.log;      #Файл ошибок.

events {
    worker_connections  1024;   #Количество соединений на рабочий процесс. Кроме того в данную секцию прописываются методы обработки соединений сервером Nginx
}

http {           #В блоке http, прописываются глобальные настройки, которые могут быть переопределены во вложенных дочерних блоках Server или Location.
    include       mime.types;                 #Включение файла с перечисленными типами данных.
    default_type  application/octet-stream;   #Тип данных по-умолчанию.

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '  #Настройка формата логов.
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    sendfile       on;  
    tcp_nopush  on;  

    keepalive_timeout  65;

    gzip  on;

    server {                             #Секция настроек конкретного виртуального сервера.
        listen       192.168.50.20:80;   #Внешний адрес и порт на которых сервер Nginx будет принимать соединения.
        server_name  nginxhost;          #Имя виртуального хоста.

        access_log  logs/nginxhost.access.log  main;

        location / {                           #Отсюда, все запросы будут отправлены на Apache.
            proxy_pass   http://127.0.0.1;     #Apache у нас на 80 порту, поэтому достаточно указать адрес. Установка необходимых заголовков, для передачи Apache имени виртуального хоста и реального IP адреса клиента.
            proxy_set_header Host $host;      
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        }

        location ~* \.(jpg|jpeg|gif|png|ico) {    #В данной секции используется регулярное выражение, под которое подпадают все файлы, с перечисленными расширениями, как видите это картинки. Nginx будет сам обрабатывать запросы попадающие в этот блок.
            root   /usr/home/test/public_html;    #Корень дерева документов для данного Location.
        }

################### Обработка ошибок ########################

        error_page  404              /404.html;
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/local/www/nginx-dist;
        }
################### Обработка ошибок ########################
    }
}

Проверяем правильность конфигурационного файла командой nginx -t.

[emerg]: open() "/usr/local/etc/nginx/logs/error.log" failed (2: No such file or directory)
configuration file /usr/local/etc/nginx/nginx.conf test failed

Ага.. ошибка. Nginx не может найти папку logs, указанную в пути для лог файла, в файле конфигурации. Просто создадим ее:

vds-admin /usr/local/etc/nginx# mkdir logs Создать директорию.
vds-admin /usr/local/etc/nginx# nginx -t Проверяем.
the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
configuration file /usr/local/etc/nginx/nginx.conf test is successful

Проверка конфигурации закончилась успешно. Запускаем веб сервер Nginx и смотрим netstat -Lan:

vds-admin /# nginx
vds-admin /# netstat -Lan
Current listen queue sizes (qlen/incqlen/maxqlen)
Proto Listen Local Address
tcp4 0/0/128 192.168.50.20.80 А вот и он.
...................................
...................................

Теперь можно проверить. В папку, которая указана у нас как корень дерева документов в настройках виртуального хоста Apache, то есть /usr/home/nginxhost/public_html, я положил небольшой файл, index.php, следующего содержания:

  1. <?php
  2. echo $_SERVER['DOCUMENT_ROOT'];
  3. ?>

Набираем в браузере адрес, на котором Nginx ожидает соединений, 192.168.50.20. Запрос сначала попадает к Nginx, в location /, оттуда будет отправлен на Apache, который и сгенерирует контент, вернув готовый ответ серверу Nginx, а Nginx в свою очередь выдаст его в браузер. В браузере мы получим:

/usr/home/nginxhost/public_html

Если заглянуть в лог файл хоста Apache, /var/log/nginxhost_custom, можно увидеть наш запрос. Если же в директорию с документами, рядом с index.php, положить какой-нибудь графический файл, например image.jpg и запросить его через браузер 192.168.50.20/image.jpg, и после этого снова проверить /var/log/nginxhost_custom, этого запроса мы там не увидим, вместо этого он появился в лог файле Nginx'а, то есть в /usr/local/etc/nginx/logs/nginxhost.access.log. Это результат работы блока Location с регулярным выражением, \.(jpg|jpeg|gif|png|ico), которое соответствует любому файлу с одним из перечисленных расширений, конфигурационного файла Nginx.

Если вы обратили внимание, в лог файле сервера Apache, IP адрес, запросов приходящие от сервера Nginx, прописываются как локальные, 127.0.0.1, то есть Apache видит адрес проксирующего сервера а не реальные адреса клиентов. Для того что-бы это исправить, необходимо установить специальный модуль

Вот мы и настроили простейший вариант связки, фронтэнд ( Nginx ) -- бакэнд ( Apache ).

P.S. Целью данной статьи не является, предоставление готового рабочего решения для какого-то конкретного сервера, это лишь описание принципа взаимодействия Nginx - Apache, на рабочем, максимально упрощенном, примере.

Комментарии

Есть ли смысл устанавливать связку Nginx(фронтэнд) - Apache(бакэнд), если на вебсервере планируется разместить несколько сайтов с CMS Joomla 1.5 - 1.7 или можно обойтись Nginx - FastCGI?

ну можно обойтись, если руки правильно заточены :)

))) это точно. Если я правильно понимаю, то можно настроить Nginx - FastCGI (для обработки php) и правильно прописать RewriteRule и настройки вирт.хостов как у вас в статье http://vds-admin.ru/nginx/zamena-rewriterule-v-nginx-dlya-razlichnykh-cms. Этого будет достаточно для правильной работы? Если появятся вопросы могу обратиться за помощью и консультацией???

да, конечно )

здравствуйте,
что-то не получилось у меня работа в такой схеме,
почти ничего не менял, но тестовый файлик пытается обработать сам гникс.
и поскольку в нем нет модуля для работы с пхп, то он его выводит как текст.

подскажите, что не так настроил?

ну так а как апач настроен, по первым ощущениям у вас апач не так настроен

Спасибо за статью! Помогли избавиться от 502 ошибки, просидел за компом 12 часов, настроил за 5 минут.

пожалуйста :)

Здравствуйте! А если апач настроен на тот же ip только другой порт, как у вас тут:

listen внешний_IP_адрес:8080

есть ли смысл в модуле rpaf_module ?

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
Регистр имеет значение
     .                           ooooooooo.                            
.o8 `888 `Y88.
.o888oo .oooo.o oooo oooo 888 .d88' oooo oooo oo.ooooo.
888 d88( "8 `888 `888 888ooo88P' `888 `888 888' `88b
888 `"Y88b. 888 888 888`88b. 888 888 888 888
888 . o. )88b 888 888 888 `88b. 888 888 888 888
"888" 8""888P' `V88V"V8P' o888o o888o `V88V"V8P' 888bod8P'
888
o888o
Введите код, изображенный в стиле ASCII-арт.