Настройка Nginx + LAMP сервера в домашних условиях. Часть 1: Настройка frontend — backend

Настройка Nginx + LAMP сервера в домашних условиях В этом цикле статей вы узнаете как грамотно настроить LAMP сервер, аля «хостинг только мощней». Мы будем использовать следующий стек: nginx — apache-mpm-itk — mod_php — mysql — linux/debian.
Буду освещать следующие темы:

  • Настройка frontend — backend
  • Расчет возможностей сервера, настройка mysql и backend
  • Рассказ об опыте на базе intel s3420gp

Совершенно уверенно могу сказать, что настройка LAMP сервера не ограничивается 6-10 командами установки и раскомментирования определенных строчек в файлах настройки.
Пример: по умолчанию nginx не дает возможности закачать на сервер тело запроса больше чем 1M. Если не настроить данный параметр, будет возникать ошибка 414 (Request-URI Too Large), при попытке добавления небольшой серии фотографий.
У apache совершенно противоположное: у него тело запроса по умолчанию не ограничено. Это делает возможным совершать пакости.

В этой статье мы познакомимся со всей настройкой досконально. В статье вы сможете найти конфигурационные файлы, подготовленные мной. Будучи педантом, мои конфигурационные файлы всегда сгруппированы по типу, например: «производительность», «генерация контента», «страницы ошибок», «сжатие», «другие настройки», «общие настройки». Мне кажется, что читаемость данных файлов становится намного лучше, если они сгруппированы.
Мы узнаем о том какие бывают простые атаки и как от них защищаться. Сразу скажу, что при базовой конфигурации frontend в лице nginx — backend apache все равно остается уязвим.

Предисловие:

Так получилось, что недавно у нас начал падать сервер. Почему-то падал он c вечера на ночь, а днем вполне себе работал. Не скажу что на нем была огромная нагрузка. Во время падений обнаружил непонятно огромные скачки выделения оперативной памяти на apache, более 700 мегов на процесс, хотя у PHP максимально стояло 256M. Сервер уходил в своппирование, после чего падал. У сервака вначале было 8G RAM, после чего поставили 16G.
До этих падений сервер работал целый год и никаких проблем не знали. У него была жуткая конфигурация сделанная на коленках, ибо c хостинга нас уже гнали. Вот его конфигурация, все из дебинских репозиториев: Apache2.2.16_mpm_itk + php5.3.0 висел в интернете за frontend и backend одновременно, без защит от возможных атак вообще. Мне удалось провести все атаки, упоминавшиеся на хабре =).
Mysql5.1 был настроен в базовой конфигурации с не оптимальным использованием RAM и все такое.
С этого момента пришлось все очень хорошо изучить. Кстати, после того как все нормально настроил, количества ненужного словоблудия в конфигах виртуальных хостов резко уменьшилось!

Начнем настройку

Репозитории бывают разные:

Первая проблема которая встала, это обновление софта. Как известно, репозитории debian имеют достаточно устаревший софт. Говорят, что они хорошо тестированы, но они реально старые! К слову я сам удивился, когда нашел эту подборку софта. Теперь репозитории LAMP я беру от сюда www.dotdeb.org/ Вот инструкция по настройке www.dotdeb.org/instructions/

Для тех кто в первый раз очень сухо:

  1. Устанавливаем debian сразу ставим галку ставить SSH сервер (больше ничего!!!), далее узнаем IP сервера за VGA монитор больше не садимся, можете сдать сервер в датацентр.
  2. Коннектимся по SSH, советую putty под win.
  3. nano /etc/apt/sources.list вставляем туда по инструкции с dotdeb. (на заметку: вставка текста в консоль из буфера windows делается правой кнопкой мыши)
  4. выполняем другие вещи по инструкции
  5. выполняем большой блок команд которые я написал ниже
  6. работаем через MC как белые люди
  7. дальше все зависит от Вас!

На заметку, вот моя конфигурация железа: Intel s3420gp, xeon x3450, 16GB ECC RDIMM, 3*1Tb 3.5″ SATA «WD BE» (2x-raid1(25G /, 20G swap, 100G /var, ~800G /home) + 1single(1Tb /mnt/unsafe)). На заметку новичкам: я жутко в свое время ступил, что поставил диски Black Edition — надо было ставить Raid Edition.

И так. Сейчас мы только что поделили диски, поставили операционную систему из минидиска debian (190Mb) и сделали настройки репозиториев. Теперь продолжим. Во время выполнения операций у вас будут вопросы от dpkg, надо на них ответить.

apt-get update
apt-get upgrade
apt-get install nginx apache2 apache2-mpm-itk php5 php5-apc php-pear php5-dev php5-gd mysql-server mysql-client php5-mysql postfix mc -y
apt-get install libapache2-mod-rpaf -y
echo all done!

nginx — фронтенд, apache2-mpm-itk — бэкенд, mod_php5.3 — язык, mysql5.5 — база данных, postfix — рассылка почты из PHP.

Составляем архитектуру системы:

Всегда известно, что без наглядной картинки настраивать систему труднее чем, если бы она была. Вначале я сам не мог себе её представить и нарисовал её только после прочтения более половины основной документации по двум серверам и немного про апачи с mysql. Сейчас я её нарисовал для читателей сразу, что бы им было нагляднее и удобнее изучать конфигурацию. Думаю, что по данной картинке будет достаточно просто анализировать узкие части системы в будущем, что позитивно скажется на поддержке системы и, возможно, ее масштабирования.
Настройка Nginx + LAMP сервера в домашних условиях
Все части картинки я буду пояснять в следующей статье. В этой статье мы раскроем настройки frontend — backend. Защита apache.

Frontend: настройка nginx

Настраивать nginx мы будем в режиме прокси. Этому есть несколько причин:

  • Защита сервера apache от атак
  • Сжатие и отдача статического контента на легковесном сервере
  • Сохранение мозгов сервера
  • Простота реализации
  • Apache mod_php работает (не намного || хуже) чем PHP FastCGI, при том, что настройка mod_php более понятна и стандартна
  • /ul>

    Конфиги в студию!

    Вот мои конфигурационные файлы которые я использую для прокси сервера: 
    То что поставилось вам от репозиториев надо безжалостно заменить на эти файлы, а так же добавить в mime расширения .docx, .pptx, .xlsx напротив соответствующих mime типов. Давайте немного посмотрим на устройство конфигов:

/nginx.conf - главный конфигурационный файл - собственно с него и начинается загрузка. В нем я оставил общие настройки сервера и импорт директорий.
/proxy_params - конфигурационный файл, для настройки nginx сервера в режима proxy. Там собраны все настройки касательно проксирования сгруппированные по группам: Базовые настройки, Защита от killapache.pl, Размер буферов, Кеширование, Другое.
/conf.d - директория в которой я сгруппировал конфигурации по каждому модулю. В частности я сгруппировал error-docs - страницы ошибок, ngx_http_core_module - базовые настройки сервера, ngx_http_gzip_module - настройки сжатия.

Я намеренно не объясняю значения параметров настроек, так как на то есть русская документация. Однако я хочу указать на некоторые из них и то, почему я выбрал именно такие параметры. Читателям же желаю подумать, какие настройки нужны для их целей, тем более искать их больше не нужно я их все сгруппировал.

  • client_max_body_size я увеличил до 64M, что бы можно было загружать на сервер разную мультимедиа — банально фотографии.
  • client_body_buffer_size — стандартный буфер я увеличил до 32k потому что по умолчанию явно не будет хватать. Часто приходится обрабатывать «большие данные (10-20к)» на входе. Вообще этот параметр должен определяться из того какой код будет выполняться на сервере. Если вы например твиттер — то вам больше 1к не нужно тратить (однако все равно надо ставить 8k что бы выронить по странице памяти 64х системы). Если вы хабрахабр, я бы поставил 8k (меньше чем значение по умолчанию), потому что там пишут комментарии часто выходящие за 1k, но в среднем меньше чем 8к (на вскидку, могу ошибаться). Что происходит, если этот параметр переполняется читать в документации.
  • large_client_header_buffers — я уменьшил тем самым сровняв с тем, что может принять остальная часть системы — apache+php.
  • worker_processes — рабочих процессов поставил по количеству ядер / 2.
  • worker_priority — поставил выше всех, что бы весь остальной бэкенд не тормозил отдачу сформированного контента.
  • server_tokens off; — не надо светить тем, что у тебя стоит =), можно попасть в беду.
  • proxy_read_timeout — я увеличил, до 300 + 20 секунд. Это чуть чуть больше чем timeout apache, который происходит через 300+10 секунд. Так сделано, что бы timeout происходил «из глубин» бэкенда, а не обрывался по непонятным причинам фронтендом. По умолчанию этот параметр 60 секунд, что порой бывает мало для тяжелых вычислений. Замечу, что php в такой конфигурации может выполняться до 300 секунд, до начала чреды таймаутов.
  • Прошу обратить внимание на директивы proxy_set_header — в файле proxy_params: они используются для того что бы установить заголовки для проксированного сервера. В частности проксированный сервер не видит какой IP адрес к нему обратился, потому что считает что к нему обращается локальный 127:0:0:1
  • Проксирую я на локальный порт 127.0.0.1:88, честно пытался найти сокеты либо костыли на основе них, но не получилось =(

Backend: настройка apache
Теперь приступим к настройке apache. Вот очередная пачка сгруппированных конфигурационных файлов: 
В файлах апача я подписал каждый параметр, скопировав его из документации, что бы было удобнее настраивать. Опять же я отправляю вас к документации для настройки для ваших потребностей и расскажу про ключевые вещи:

  • файл ports.conf: прослушиваем порты 88 и 443.
  • дополнительно устанавливаем libapache2-mod-rpaf (уже сделали выше). Он служит для того, что бы расшифровывать заголовки, которые передает нам проксирующий сервер. Да те самые заголовки, которые мы устанавливали директивой proxy_set_header.
  • DeflateCompressionLevel 1 (файл /mods-enabled/deflate.conf) в defline я установил степень сжатия = 1, я решил сильно не жать. В любом случае, если у вас есть лишние рабочие руки на сервере, то почему бы не 9-ть?.
  • Я активировал модуль mod_headers и в файле conf.d/security зарезал некоторые заголовки для безопасности, для хостов висящих на 443-м порте. Подробности в конфигах. Не знаю зачем я этот порт оставил не проксированным, но это факт. Просто руки что-то не дошли, либо я побоялся, а потом уже руки не долшли. В любом случае обычным смертным запрещено к нему обращаться. Кстати с апачи версии >= 2.2.21 эту проблему решили специальной настройкой на уровне ядра.
  • ServerTokens Prod, ServerSignature Off — опять же не светим вкусными местами.
  • В файле secutiry в секции directory я описал максимально много разных настроек, что бы было меньше словоблудия в файлах виртульных хостов.
  • TimeOut 310 — уже писал почему 310 секунд.
  • RLimitMEM — интересная штука, советую почитать. Позволяет ограничивать память которую потребляет апач в целом. Так же интересны другие R* параметры
  • DefaultType application/octet-stream — если мы не знаем что отдаем, то пускай это будут бинарники.
  • AddDefaultCharset Off — лучше не включать, если вы не уверены в том, что у вас все в одной кодировке

С тем на что нужно обратить внимание я закончил. Теперь давайте перейдем к рассмотрению mpm-itk модуля выбранного для выполнения задач на хостинге.
Дело в том, что данный модуль удобен тем, что при каждом новом обращении к серверу создается новый процесс и он переключается на определенного пользователя, допустим на www-ru-example. То есть этот пользователь «запирается» в своем каталоге и никакие скрипты никуда попасть не смогут, при учете того что вы правильно настроили операционную систему. Замечу, что многие файлы настроек по умолчанию в debian открыты для чтения для всех!!!..
Интересна история этого MPM. Дело в том, что он был сделан на основе mpm prefork, это означает, что все настройки для prefork действуют и на itk. Соответственно в моем конфигурационном файле вы это можете прослеживать.
Прошу обратить внимание на MaxClients 150, эти те самые максимальные 150 пользователей, которые могут быть при обращении к бэкенду. Так же прошу обратить внимание MaxRequestsPerChild. По умолчанию он равен нулю. Советуется устанавливать его хотя бы ограниченным — это уменьшает возможность утечки памяти.

Еще одна важная вещь в mpm-itk это nice value. Это значение я установил равным -2. Я сделал именно так, потому что как только БД отдала результат, PHP должен моментально его до конца сформировать и отдать. Прошу заметить иерархию nice-value.
nginx = -5, apache = -2, mysql = 0. Это сделано для того, что бы максимально быстро формировать контент и отдавать пользователю. Операционная система должна вытеснить не приоритетные процессы на потом.

Хотелось бы сказать пару слов о базовой защите апачи.
Есть несколько типов атак, которые должен знать любой сисадмин: killapache.pl, slow post, slow lori. Все эти атаки очень просто производятся на открытый апач. От killapache.pl спасает mod_headers или nginx, где можно закрыть проблему запретив определенные заголовки. Говорят что killapache.pl это проблема самого протокола. slow post, slow lori это идентичные атаки, одна делается при передаче большого POST, с очень медленным каналом, другая делается передачей сгенерированного контента к клиенту очень медленным каналом. Эти атаки не страшны для сильного мускулистого и жилистого сервера nginx, которым мы прикрылись. Для апача это смертно подобно, например песочница PHP чистится после того как сервер отдал все данные, теперь представьте сколько можно сожрать памяти.

В конце хочу сказать, что в конфигурационных файлах я прислал просто файлы. Не забывайте создавать симулинки в частности для каталогов mods-enabled из mods-available, sites-* и др.

Спасибо за прочтение, надеюсь понравилась моя подборка конфигов. Многие другие вещи я попробую осветить в других топиках. Например настройка бэкенда (php — mysql) и расчет возможностей сервера. Если первая и вторая статья будет интересна, то я могу выкатить еще 2 статьи: «система учета пользователей», «опыт касательно выбора железа начального уровня», «разное про работу на сервере». В финале я могу разработать набор утилит для быстрой настройки сервера по указанным мною статьям.