Веб-сервер на связке nginx+apache

Разворачиваем веб-сервер под операционной системой Linux, который будет использовать одновременно nginx и apache.

Пусть имеется аппаратная платформа, на которой уже установлен CentOS.

Настроим связку apache+nginx. На передовую (front-end) выставляем лёгкий и высокопроизводительный nginx, который будет обрабатывать запросы к статическому контенту (картинки, стили, js и т.п.). В тылу (back-end) нас будет страховать apache, задачей которого является предоставление динамического контента (в основном, PHP).

top-nginx-apache

Безусловно, возникает законный вопрос, нельзя ли обойтись без apache вообще? Действительно, ничего не мешает настроить совместную работу nginx+php+mysql (вызываем PHP в режиме FastCGI с помощью php-fpm). Производительность такой системы будет ещё выше. Но есть и серьезный недостаток: большинство стандартных движков сайтов ориентировано непосредственно на работу под apache (правила доступа к различным директориям сайта настраиваются в файле .htaccess); а ввиду того, что nginx не обрабатывает .htaccess, без доработок такие сайты под nginx работать не будут. Причем, если переработка одного сайта является вполне выполнимой технической задачей, то обслуживание нескольких сайтов (особенно чужих), становится настоящей проблемой.

Итак, жертвуем экстремальной производительностью, но сохраняем поддержку .htaccess.

Устанавливаем apache, mysql, php. Для этого нам пригодится yum и стандартные репозитории.

yum -y install httpd mysql mysql-server php php-mysql php-mbstring php-cli

Установка nginx чуть сложнее, придётся сходить на сайт разработчика и прочитать методику установки. К счастью, под распространенные дистрибутивы (CentOS и подобные), разработчик предоставляет готовые пакеты.

Настраиваем всю связку:

  • Конфигурация mysql
  • Конфигурация php
  • Конфигурация apache
  • Конфигурация nginx.

Теперь рассмотрим каждый шаг подробно.

Конфигурация mysql

Рассмотрена в соответствующей статье.

Конфигурация php

Практически не требуется, в деталях описана в отдельной статье. Главное не забыть про shorttag: short_open_tag = On.

Конфигурация apache

Так как на передовую мы выдвигаем nginx, значит именно он будет работать на стандартном порту 80, а обращение к apache будет проксироваться через любой другой порт. Я выбрал 8080.

Модифицируем файл глобальных настроек. Я привожу только самые важные параметры, которые надо проверить:

Timeout 60
KeepAlive Off
# MaxKeepAliveRequests 100
# KeepAliveTimeout 10

StartServers 2
MinSpareServers 2
MaxSpareServers 4
ServerLimit 6
MaxClients 10
MaxRequestsPerChild 800

# Слушаем нестандартный порт,
# так как у нас на передовой nginx
Listen 127.0.0.1:8080
# Пользователь и группа
User apache
Group apache
# Определяем порт
NameVirtualHost *:8080

Интересно, что KeepAlive следует отключать (спасибо за наводку внимательному читателю Mike). Производительность системы будет повышаться, если процесс httpd, отдав динамическое содержимое, будет тут же освобождаться.

Важно завести пользователя и группу, от которых будут работать в связке две службы: и nginx, и httpd. Естественно, это должен быть один и тот же пользователь как для httpd, так и для nginx во избежание конфликтов! Я для этих целей использую пользователя и группу apache; в результате httpd работает из-под "своего" имени, а nginx вынужден работать под чужим именем.

Следующим шагом будет настройка виртуальных серверов. Каждый виртуальный сервер будем настраивать, создавая для него отдельный конфигурационный файл в /etc/httpd/conf.d/, причем необходимо следить, чтобы расширением являлось именно .conf. Предположим, создаётся виртуальный сервер для сайта drach.pro, тогда потребуется файл /etc/httpd/conf.d/drach.pro.conf со следующим содержимым:

# Слушаем выбранный порт:
<VirtualHost *:8080> ServerName drach.pro
ServerAlias www.drach.pro
ServerAdmin Этот адрес электронной почты защищен от спам-ботов. У вас должен быть включен JavaScript для просмотра.
DocumentRoot /var/www/html/drach.pro
CustomLog /var/log/httpd/drach.pro_access.log combined
ErrorLog /var/log/httpd/drach.pro_error.log

<Directory "/home/drach.pro/www">
AllowOverride All
Options +Includes
</Directory>
</VirtualHost>


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

Теперь десерт! Не достаточно настроить apache на обычную работу, необходимо корректно обрабатывать REMOTE_ADDR заголовка. Для этих целей устанавливаем и настраиваем RPAF (mod_rpaf соответствует первой версии apache, а mod_rpaf2 - второй).

Без RPAF будем иметь REMOTE_ADDR не пользовательский, а IP-адрес сервера с передовой (это nginx). RPAF будет обрабатывать заголовок X-Forwarded-For, который получен от nginx и генерировать корректный REMOTE_ADDR.

Таким образом заголовок REMOTE_ADDR снова имеет пользовательский IP! Например, для моих целей это крайне важно, так как приходится наблюдать за пользователями и вести подробные логи для отчётов.

Устанавливаем модуль RPAF, для чего его придётся найти в интернете отдельным пакетом под наш дистрибутив. Есть альтернативный путь: подключить хранилище Atomic repo и использовать yum. Затем настраиваем RPAF, создавая и редактируя /etc/httpd/conf.d/mod_rpaf.conf:

LoadModule rpaf_module modules/mod_rpaf-2.0.so
RPAFenable On
# Enable reverse proxy add forward RPAFproxy_ips
YOUR_PROXY_SERVER_IP_LIST_OR_ONE_IP
# which ips are forwarding requests to us
RPAFsethostname Off
# let rpaf update vhost settings
# allows to have the same hostnames as in the "real"
# configuration for the forwarding Apache
RPAFproxy_ips 127.0.0.1
RPAFheader X-Real-IP

После конфигурации необходимо перезапустить Apache.

Конфигурация nginx

Описываем глобальный файл конфигурации /etc/nginx/nginx.conf:

user apache;
worker_processes auto; разрешаем серверу выбирать количество процессов!
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
}


http {
include /etc/nginx/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"';

# Журналирование будет индивидуальное для всех сайтов:
# access_log /var/log/nginx/access.log main;

sendfile on;
client_max_body_size 24M;
#tcp_nopush on;
keepalive_timeout 65;

gzip on;
# Минимальная длина ответа, при которой модуль будет жать, в байтах
gzip_min_length 1100;
# Разрешить сжатие для всех проксированных запросов
gzip_proxied any;
# Запрещает сжатие ответа методом gzip для IE6
gzip_disable "msie6";
# Уровень gzip-компрессии
gzip_comp_level 8;

# 1) MIME-типы которые необходимо жать
#gzip_types text/plain text/html text/xml application/xml application/x-javascript text/javascript text/css text/json;
# 2) Если у вас появляются предупреждения, типа "duplicate MIME type text/html", то стоит исключить text/html
gzip_types text/plain text/xml application/xml application/x-javascript text/javascript text/css text/json;

# Хватаемся за соломинку:
#gzip_types text/html text/xml text/css application/x-javascript text/javascript;

include /etc/nginx/conf.d/*.conf;
}

Теперь конфигурируем виртуальные хосты! Причем, поступаем профессионально: конфигурационные файлы складываем в /etc/nginx/conf.d: например, для сайта drach.pro заводим отдельный файл /etc/nginx/conf.d/drach.pro.conf:

# A virtual host drach.pro

server {

# listen drach.pro:80;
listen 80;
server_name drach.pro;

# Ведём журнал доступа:
access_log /var/log/nginx/drach.pro_access.log;

# Разделяем статику и динамку, статику храним в кэше 10 дней:
location ~* \.(jpg|jpeg|gif|png|ico|css|bmp|swf|js|doc|docx|pdf|xls|xlsx|rar|zip|tbz|7z|exe)$ {
root /var/www/html/drach.pro/;
expires 10d;
}
# htaccess и htpasswd не отдаем:
location ~ /\.ht {
deny all;
}
# Мы хотим видеть статистику при обращении к папке /stat
location = /stat {
stub_status on;
access_log off;
# allow xx.xx.xx.xx;
# deny all;
}
location / {
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
log_not_found off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

Конец. Достаточно перезапустить все службы и убедиться, что веб-сервер работает!

service httpd restart && service nginx restart

Отслеживаем доступ к серверу в реальном времени:

tail -f /var/log/nginx/drach.pro_access.log

или

tail -f /etc/httpd/logs/drach.pro_access.log

Ежели в консоли браузера появляется ERR_INCOMPLETE_CHUNKED_ENCODING (обычно это бывает, если файлы css и js генерируются "на лету"), необходимо проверить права и владельца директории /var/cache/nginx/proxy_temp. Также есть смысл убрать эти два расширения из разрешённых статических типов файлов для nginx.

 

Ежели в журнале ошибок появляется upstream response is buffered to a temporary file, следует в файл глобальной конфигурации nginx добавить proxy_max_temp_file_size 0; в секцию http.

13 комментарии

  • Аррис

    написал Аррис

    Суббота, 03 Январь 2015 12:35

    А в чем тайный смысл
    short_open_tag = On
    ?

  • Аррис

    написал Аррис

    Суббота, 03 Январь 2015 12:36

    Я знаю, что означает эта директива. ЗАЧЕМ разрешать короткие теги ПХП?

  • Владимир Драч

    написал Владимир Драч

    Воскресенье, 04 Январь 2015 20:36

    Подавляющее большинство современных CMS несут в коде сокращённый вариант директивы. Ориентируясь на них, я предлагаю сразу выставить значение "On". Ибо, как правило, заранее не известно, что именно будет запускаться на веб-сервере его пользователями.

  • сергей

    написал сергей

    Пятница, 06 Февраль 2015 12:36

    Что за файлик vhost.conf?
    Нет такого.

  • Владимир Драч

    написал Владимир Драч

    Суббота, 07 Февраль 2015 17:56

    Если нет, можно создать самостоятельно, путём копирования конфигурационного файла того сайта, который будет являться сайтом по умолчанию. В теле статьи размещена ссылка с примером.

  • Mike

    написал Mike

    Воскресенье, 15 Февраль 2015 17:32

    Странные советы в статье. Она ориентирована на новичков, но человек, который начинает в CentOS, зависнет на пункте с установкой mod_rpaf. Его нет в стандартных репозитариях.
    Для этого нужно подключить Atomic repo.

    Когда Apache за Nginx, надо отключать KeepAlive, так как между Nginx и Apache соединения держать просто не имеет смысла.
    Зачем в связке nginx+apache приведённые значения?

    StartServers 8
    MinSpareServers 6
    MaxSpareServers 21
    ServerLimit 256
    MaxClients 20

    Первое: я всегда считал, что ServerLimit и MaxClients должны быть равны.
    Второе: за глаза хватит значений:

    StartServers 1
    MinSpareServers 1
    MaxSpareServers 3
    ServerLimit 5
    MaxClients 5
    MaxRequestsPerChild 1000

    Apache отъедает на один процесс ~30 Мб памяти и, с последними настройками, он будет потреблять скромные ~150 Мб.
    Вот тогда связка nginx+apache имеет смысл, т.к. сервер не умрёт при большом количестве коннектов.

    И последнее моё имхо: не вижу смысла выставлять gzip on; при большом количестве коннектов - лишняя нагрузка на процессор.

  • Владимир Драч

    написал Владимир Драч

    Понедельник, 16 Февраль 2015 12:31

    Mike, спасибо за детальный анализ материала!
    Исправлены пункты об установке rpaf и KeepAlive. Скорректированы значения в конфигурационном файле Apache в сторону уменьшения.
    Что касается компрессии gzip, думаю, каждый должен решать для себя сам, принимая во внимание аппаратные мощности и нагрузку на сервер. Мои эксперименты показывают, что значение "4" незначительно увеличивает нагрузку на процессор при существенном снижении траффика.

  • Дмитрий

    написал Дмитрий

    Среда, 27 Май 2015 15:09

    Вопрос от начинающего в CentOS да и вообще в веб-серверах:
    куда сайты-то класть?

  • Владимир Драч

    написал Владимир Драч

    Пятница, 29 Май 2015 14:52

    Дмитрий, если будете устанавливать веб-сервер по моей методике, то все файлы сайтов надо складывать в директорию
    /var/www/htm/имя-сайта/

  • Kennedy

    написал Kennedy

    Четверг, 01 Октябрь 2015 12:12

    Несмотря на то, что эта тема изрядно избита и  в интернете по этому поводу написано уйму статей, я всё же не могу просто обойти эту тему стороной и ничего про это не сказать и пусть даже мой пост-manual, возможно, будет не самым длинным и подробным, но зато я постараюсь описать ключевые аспекты настройки связки (взаимодействия) веб серверов Nginx и Apache на одном сервере.

  • Anton

    написал Anton

    Вторник, 08 Ноябрь 2016 17:42

    Изящная методика. Благодарю за материал.

  • Харьковчанин

    написал Харьковчанин

    Пятница, 03 Ноябрь 2017 11:45

    В отличие от apache веб сервер nginx характерен тем, что прослушиваемые порты для него надо прописывать для каждого сервера . Т.е. порт 80 надо писать для каждого виртуального хоста.

  • Владимир Драч

    написал Владимир Драч

    Воскресенье, 05 Ноябрь 2017 15:56

    Спасибо за отзывы, коллеги!

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

Другие материалы в этой категории:

Go to top