Содержание
Эта статья является продолжением предыдущей статьи (в которой я рассказывал о настройке небольшого LAMP-хостинга на VPS под управлением Debian).
Зачем нужен еще и nginx — можно почитать здесь и в других источниках.
Программа на сегодня такая:
- Сначала делаем, чтобы все запросы шли через nginx (делаем тупой прокси)
- Изучаем как отдавать статичный контент в обход Апача
- Настраиваем ограничение нагрузки
В заключение я немного порассуждаю о возможных проблемах и подводных камнях.
Вставляем nginx перед Apache
apt-get install libapache2-mod-rpaf nginx
Теперь надо перевесить Апач на порт 81 и спрятать от внешнего мира. В /etc/apache2/ports.conf меняем:
NameVirtualHost *:81 Listen 127.0.0.1:81
Во всех конфигах внутри /etc/apache2/sites-available тоже меняем порт:
<VirtualHost *:81>
Теперь переходим в /etc/nginx.
Удаляем «заводской» сайт:
- sites-available/default
- sites-enabled/default
Вместо него добавляем наш собственный:
touch /etc/nginx/sites-available/apache_proxy
Внутрь помещаем:
server { listen 80 default; server_name localhost; location / { proxy_pass ; proxy_set_header <a href="http://en.wikipedia.org/wiki/X-Forwarded-For" data-mce-href="http://en.wikipedia.org/wiki/X-Forwarded-For">X-Forwarded-For</a> $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } }
Сохраняем и делаем его «enabled»:
ln -s /etc/nginx/sites-available/apache_proxy /etc/nginx/sites-enabled/apache_proxy
Линк приходится создавать руками — утилит вроде a2ensite
тут к сожалению нет.
Перезапускаем сервера:
/etc/init.d/apache2 restart /etc/init.d/nginx restart
После всех этих манипуляций сайты должны продолжить работать без изменений.
Статика в обход Апача
Пора получить от nginx какую-нибудь пользу. Вносим вот такие изменения в недавно созданный файл apache_proxy:
server { listen 80 default; server_name localhost; <b>location /**static**/<em>domain1.com</em>/ { internal; alias /home/<em>user1</em>/<em>domain1.com</em>/www; expires 24h; }</b> location / { <b>if ($http_host = <em>domain1.com</em>) { set $my_static_location <em>domain1.com</em>; } if ($my_static_location) { rewrite ^(.*\.(css|js|png|jpg|gif))$ /**static**/$my_static_location/$1; }</b> proxy_pass ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } }
Применяем:
/etc/init.d/nginx reload
Теперь статичные файлы должны отдаваться напрямую. Убедиться в этом можно через dev tools браузера: в заголовках ответа появилось max-age=86400
и исчез ETag, который генерировал Апач.
Список расширений (в директиве rewrite
) можно дополнить по собственному желанию: doc, xls, mp3, flv, ico, txt, html, xml, pdf, zip и многое другое.
Важным нюансом является то, что процесс nginx должен иметь доступ к отдаваемым файлам (на чтение конечно). Если вы в целях безопасности делаетеchmod 0750
домашним директориям пользователей, то это создаст препятствия.
Теперь пара слов о конфиге. «Легко видеть», что для каждого домена, для которого мы хотим отдавать статику, заводится internal location, указывающий на web-root. Далее идет выбор этого location-а и перекидывание на него запросов за статикой.
Такой подход позволяет сохранять конфиг компактным — не надо создавать параллельные конфигурации серверов в Apache и nginx. В то же время не теряется гибкость: вы сами решаете, для каких доменов вам это надо, и у вас есть свобода в настройке путей, кеширования и других фишек для каждого домена отдельно.
Ограничение нагрузки
limit_req
— еще одна плюшка, которую может нам дать nginx:
limit_req_zone $pid zone=proxy_global:64k rate=10r/s; server { listen 80 default; server_name localhost; location /**static**/domain1.com/ { internal; alias /home/user1/domain1.com/www; expires 24h; } location / { if ($http_host = domain1.com) { set $my_static_location domain1.com; } if ($my_static_location) { rewrite ^(.*\.(css|js|png|jpg|gif))$ /**static**/$my_static_location/$1; } proxy_pass ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; limit_req zone=proxy_global burst=100; } }
Внесенные изменения ограничивают нагрузку на Апач до 10 запросов в секунду.burst=100
означает, что «неуспевшие» выстраиваются в очередь, но когда длина очереди перевалит за 100, их начнут отстреливать (HTTP 503 Service Unavailable).
Числа, разумеется, надо подбирать в зависимости от нагрузки и мощности сервера.
Обратите внимание, что при описании зоны я использовал $pid
вместо «классического» $binary_remote_addr
. Таким образом, нагрузка ограничивается глобально, а не для каждого пользователя отдельно.
Не знаю, защитит ли такая мера ваш любимый VPS от DDoS-атак, но завалить путем зажатия F5 его станет сложнее.
Возможные проблемы
Теперь порассуждаем о возможных обратных сторонах медали.
Файлы, которые nginx будет отдавать напрямую, отбираются достаточно примитивно и прямолинейно — по расширению файла. И здесь кроются грабли:
- Если файл находится в папке, доступ к которой ограничен средствами .htaccess, то очевидно эти ограничения перестанут работать, т.к. nginx про этот .htaccess ничего не знает.
- При использовании mod_rewrite за статичным с виду урлом может скрываться динамика: например, /something.json, /something.xml и something.html, отдающие одинаковый контент в разных форматах, или перехват запросов за картинками с целью встраивания их в html-рамочку. Вариантов полно.
Именно поэтому отдача статики не включена по умолчанию, а прописывается по условию. В более сложных сценариях придется отказаться и от центрального$my_static_location
, тщательно подбирая регулярные выражения для rewrite-правил под конкретный случай.
Теперь вы предупреджены, а как известно предупрежден значит вооружен. Так что используйте nginx во благо, а не во вред!