Debian.pro

Блог для пользователей и администраторов Debian


Большой мануал: часть 18. Подготавливаем apache2.

Эта статья — часть Большого Мануала по настройке lamp-сервера на debian.

Предыдущая часть цикла — Настраиваем SSL в nginx и получаем A-rate.

Следующая часть цикла — Создаём конфиг для нашего сайта в apache2.

Для того, чтобы apache мог работать вместе с nginx, его нужно немного настроить. Ну и заодно немного пооптимизируем его работу в плане «пожрать памяти».

Первым делом, нам нужно запустить апач обратно. Мы его отключали, когда ставили nginx. По дефолту и apache, и nginx слушают 80-й порт. Но нам-то нужно, чтобы апач работал вместе с nginx-ом, при этом nginx слушал дефолтные порты и мог ходить в апач для обработки тех запросов, которые сам nginx обработать не сможет.
Для этого нам нужно изменить файл /etc/apache2/ports.conf. Файл после наших шаловливых ручек должен выглядеть так (всё, что там было, можете смело сносить):

NameVirtualHost 127.0.0.1:81
Listen 127.0.0.1:81

<IfModule mod_ssl.c>
    Listen 127.0.0.1:444
</IfModule>

<IfModule mod_gnutls.c>
    Listen 127.0.0.1:444
</IfModule>

Так апач станет слушать 81й порт (при этом только на lo, чтобы доступа снаружи получить к нему было нельзя). Если мы включим ssl в апаче (бессмыссленная затея в нашей схеме, но мало ли) — то добавится ещё и 444й порт.

Теперь нужно разобраться с тем, что апач «не будет знать» про ip-адреса пользователей. С его точки зрения, единственным клиентом, приходящим по http, будет nginx (с локалхоста). Т.к. схема фронт-бэкэнд в http заложена ещё в лохматых 90-х (имхо, в тот момент, когда появились первые proxy, которые ещё не реверсные были), со временем появились 2 стандартных заголовка, в которых фронтэнд (в нашем случае — nginx) может передать ip-адрес клиента и «цепочку proxy-серверов». Заголовки эти, соответственно, называются X-Real-IP и X-Forwarded-For. Когда будем настраивать вхост в nginx, мы настроим передачу этих заголовков, а пока нам нужно «научить» apache использовать их.
До версии 2.3 включительно индейцу для этого нужен был модуль rpaf (соответственно, если у вас debian 7, то включайте только rpaf). Начиная с 2.4 для корректной обработки двух заголовков нужно уже 2 модуля — remoteip и rpaf. Бытует мнение, что в 2.4 достаточно только remoteip, но на практике остаются места, в которых этот модуль не отрабатывает (я точно уже не помню где, но в env апача без rpaf в 2.4 всё равно в каких-то переменных остаётся 127.0.0.1). Скорее всего, в 2.5 нужен будет только remoteip.

Эти модули лежат в пакетах apache2 (remoteip) и libapache2-mod-rpaf. Первый пакет у вас точно есть, а второй на всякий случай проверьте — мог и потеряться.
Включаем модули (может поругаться на то, что модуль уже включен — ну и ладно):

root@server:~# a2enmod rpaf
root@server:~# a2enmod remoteip

Так же нужно создать файл /etc/apache2/conf-available/remoteip.conf

RemoteIPHeader X-Real-IP
RemoteIPTrustedProxy 127.0.0.1

И на всякий случай проверить, что приехало в файл /etc/apache2/mods-available/rpaf.conf , он должен быть примерно таким (без учета комментариев):

<IfModule rpaf_module>
    RPAFenable On
    RPAFsethostname On
    RPAFproxy_ips 127.0.0.1 ::1
</IfModule>

Важно так же включить mod_rewrite. Собственно, htaccess у популярных cms состоит чуть более, чем полностью, из параметров, которые используют именно этот модуль. За каким-то чертом в некоторых версиях пакета с апачем он выключен по умолчанию — в том числе и сегодня, когда я пишу статью (сам модуль лежит в пакете apache2):

root@server:~# a2enmod rewrite

На этом мы закончили с минимальной настройкой, apache будет работать корректно. Всё, что в этой статье дальше — это небольшой тюнинг. Дальше нужно делать всё аккуратно, если вы не поняли к чему оно — не делайте. Если дальше тупо копипастить — то есть шанс получить не работающий апач.

Для неопытных администраторов на этом месте стоит просто порестартить апач и переходить к следующей статье:

root@server:~# apachectl restart

или

root@server:~# /etc/init.d/apache2 restart

Оосновная (на мой вкус — единственная значимая) крутилка апача на тему производительности/затрат ресурсов — это количество запущенных процессов. В апаче 2.4 для режима работы MPM prefork (а именное его мы используем, так как используем mpm-itk) упакованном в debian8 их количество настраивается в файле /etc/apache2/mods-available/mpm_prefork.conf
В MPM prefork apache запускает процесс на обработку каждого запроса (или отдаёт запрос одному из запущенных (Spare) свободных процессов). Это не самый быстрый режим работы, особенно если у вас нет свободных процессов, самый затратный по памяти, но нам действительно нужен mpm-itk — это самый универсальный режим работы. Можно использовать MPM worker (он экономичнее по памяти), но тогда мы не сможем запускать разные вхосты от имени разных пользователей. С другой стороны, на современных тазиках без приборов разницы не видно вообще.
В debian7 и ранее эти параметры находились прямо в /etc/apache/apache2.conf (где-то ближе к началу файла). Собственно, вне зависимости от того, в каком конфиге эти параметры, нам нужно искать примерно такое:

<IfModule mpm_prefork_module>
      StartServers 5
      MinSpareServers 5
      MaxSpareServers 10
      MaxRequestWorkers 150
      MaxConnectionsPerChild 0
</IfModule>

StartServers — количество процессов при старте апача.
MinSpareServers — минимальное количество «свободных» (не занятых обработкой запроса прямща) процессов
MaxSpareServers — максимальное количество «свободных» процессов.
MaxRequestWorkers — максимальное количество процессов, которые apache сможет запустить
MaxConnectionsPerChild — количество запросов в один процесс, спустя которое процесс перезапускается независимо от количества процессов

Цифры выше — это дефолт (по крайней мере, в deb8). Запускаем 5 процессов, следим за тем, чтобы у нас было как минимум 5 свободных процессов, если станет больше 10 свободных — начинаем их убивать. Если запущено в общей сложности 150 процессов — перестаём запускать новые, что бы ни случилось. Ну и автоперезапуск процессов отключен.

Теперь о том, как тюнить. Один процесс занимает примерно 10 мегабайт памяти. То есть, в дефолтной конфигурации апач может потребить не больше полутора гигабайт памяти (при таком потреблении памяти он сможет обслуживать до 150 одновременных запросов. На всякий случай напомню, что «запрос» в нашей конфигурации — это время, которое затрачено на генерацию страницы апачем. Даже если за страницей пришел медленный клиент (с мобилки, например), то nginx всё равно скачает эту страницу сразу после её генерации почти мнгновенно и будет отдавать её медленному клиенту сколько понадобится. А процесс апача будет свободным. Ну и само собой, тупо открытые страницы в браузере — это не «одновременные» запросы, если на странице ничего в данный момент с апача не подгружается). Минимальное потребление памяти — 60 мегабайт на воркеры (как только в апач придет хоть какой-то запрос — он в фоне запустит 6й процесс, чтобы было 5 свободных) + 25 на мастер-процесс.
В итоге, если у вас на сервере есть полтора гигабайта свободной памяти после установки всего софта — можно покормить собаку и ничего не делать. Скорее всего, апачу они никогда не понадобятся.
Если вы испытываете недостаток памяти — то стоит снижать цифру MaxRequestWorkers, чтобы система не уперлась по памяти.
Если памяти у вас много — то можно выкручивать цифры MaxSpareServers и MaxRequestWorkers вверх (само собой, если у вас и количество посетителей соответствующее — на бложеке с одним запросом в минуту никакого смысла в этом нет).
Если у вас бывают наплывы одновременных запросов — крутите вверх MinSpareServers, чтобы свободных процессов было больше. Вообще лучше, если эта цифра будет примерно соответствовать максимальному количеству запросов в апач в секунду, с которым вы в теории можете столкнуться (или уже столкнулись).
MaxConnectionsPerChild вам нужно выставлять в том случае, если апач у вас утекает по памяти (бывает из-за кривых модулей, или из-за кривого php-кода). Чем быстрее утекает — тем меньше ставьте цифру (только учтите, что ноль — это отключение рестарта процессов, которые обработали много запросов).

Теперь на счёт CPU. Здесь на практике тюнить нечего — потребление CPU зависит от того, насколько оптимально написан ваш код на php. Можно выиграть за счет оптимизации базы (когда php-код ждет ответ от базы — такты cpu на это всё равно уходят, да и сам запрос внутри mysql может хорошо кушать cpu), можно выиграть за счет кешей в коде (или внешних кешей, как, например apc, который мы уже поставили), за счет использования memcache вместо базы для «горячих» данных. Но всё это — не настройки апача, само собой.

Мы попробуем отключить некоторые модули. Если вы не уверены, что модуль вам не нужен — не отключайте его. Отключение модулей экономит немного памяти/cpu на каждый процесс, но после отключения модулей можно столкнуться с «Internal server error», т.к. искомый модуль мог использоваться в конфигурации или в htaccess (понять, какой из модулей выключать было не нужно, можно в логах /var/log/apache2/other_vhosts_access.log и /var/log/apache2/error.log).

Самый бесполезный модуль — cgi (в deb8 уже отключен из коробки, в deb7 и раньше нужно отключать самому). Никто cgi давно не использует. Если используете (хм?) — то не отключайте, понятное дело.

root@server:~# a2dismod cgi

Достаточно бесполезный модуль autoindex. Если вам не нужно отображать листинг каталогов — выключайте его. Для всех запросов к каталогам (например, example.com/dir/) апач будет отвечать «404 Not found». Само собой, мы не отключаем индексные файлы (которые на таких запросах будут отдавать index.php/index.html из каталога). Ну а запросы к несуществующим каталогам у вас, скорее всего, обрабатывает php. (а смотреть, что у нас там в существующих каталогах валяется мимо проходящим людям нахрен не нужно). Но на всякий случай ещё раз — отключайте только если уверены, что он не вам точно не нужен.

root@server:~# a2dismod -f autoindex

Достаточно бесползные модуль для нашего случая — deflate. Этот модуль сжимает ответы клиенту для экономии трафика (при этом жрет cpu и немного памяти). Зачем нам сжимать трафик до единственного клиента на локалхосте в лице nginx-а — непонятно. Поэтому его можно отключать.
Правда, я часто сталкиваюсь с тем, что где-то в скачанных из интернета htaccess-файлах попадаются параметры этого модуля и apache начинает InternalServerError-ить. Либо меняйте htaccess, либо включайте модуль, либо ещё что. В любом случае, nginx будет жать нужный трафик до клиентов в gzip, а сжатие апачем до клиентов «не дойдет».

root@server:~# a2dismod -f deflate

Есть смысл отключить модуль filter (опять же, до тех пор, пока он не понадобится в вашем коде/на вашем сайте):

root@server:~# a2dismod -f filter

Так же из коробки до сих пор включают модуль status, которым никто толком не пользуется. Этот модуль позволяет по http показывать некоторую статистику. Можете попытаться настроить его, но скорее всего вам будет лень этим заниматься. Так что:

root@server:~# a2dismod status

В итоге минимальный набор модулей, которые я не отключал ни разу в жизни, у меня выглядит так:

root@server:~# ls -1 /etc/apache2/mods-enabled/*.load
/etc/apache2/mods-enabled/access_compat.load
/etc/apache2/mods-enabled/alias.load
/etc/apache2/mods-enabled/auth_basic.load
/etc/apache2/mods-enabled/authn_core.load
/etc/apache2/mods-enabled/authn_file.load
/etc/apache2/mods-enabled/authz_core.load
/etc/apache2/mods-enabled/authz_host.load
/etc/apache2/mods-enabled/authz_user.load
/etc/apache2/mods-enabled/dir.load
/etc/apache2/mods-enabled/env.load
/etc/apache2/mods-enabled/mime.load
/etc/apache2/mods-enabled/mpm_itk.load
/etc/apache2/mods-enabled/mpm_prefork.load
/etc/apache2/mods-enabled/negotiation.load
/etc/apache2/mods-enabled/php5.load
/etc/apache2/mods-enabled/remoteip.load
/etc/apache2/mods-enabled/rewrite.load
/etc/apache2/mods-enabled/rpaf.load
/etc/apache2/mods-enabled/setenvif.load

На этом с ломанием апача закругляемся. Счаз я вдолюблю ещё кофе и напишу про конфиги виртуальных хостов. Ну а вы это через недельку почитаете.

20.06.2016 byinkvizitor68sl|big-manual

Комментарии (1):

  1. Роман :

    Подскажите в чем может быть проблема remoteip включен, в remoteip.conf все тоже самое что в этой статье но в логах индейца все равно внешний ip сервера а не посетителя пишет.
    В конфиге nginx проверил строчки
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    все присутствует где еще можно посмотреть в чем проблема?

Написать комментарий