Виртуальные хосты: несколько сайтов на одном сервере
Один сервер — десятки сайтов. Nginx разбирает, кому какой запрос, по заголовку Host, как почтальон по адресу на конверте.
«server_name — это имя на конверте. listen — это дверь, в которую стучатся. Nginx сопоставляет одно с другим.»
На одной машине обычно крутится не один сайт. Nginx разделяет их с помощью виртуальных хостов — блоков server. Каждый блок описывает один сайт: на каком порту слушать и на какое доменное имя отвечать.
Два ключевых параметра
listen— какой порт (и адрес) слушать:listen 80;илиlisten 443 ssl;.server_name— на какие доменные имена отвечает этот блок:server_name example.com www.example.com;.
http {
server {
listen 80;
server_name site-a.com;
root /var/www/site-a;
}
server {
listen 80;
server_name site-b.com;
root /var/www/site-b;
}
}
Оба слушают порт 80, но отвечают разным доменам. Браузер в каждом HTTP-запросе шлёт заголовок Host: site-a.com, и Nginx по нему выбирает нужный server-блок.
Как Nginx выбирает блок
Запрос: GET / Host: site-b.com
|
v
+-------------------------------+
| все server с listen 80 |
| |
| server_name site-a.com ---- нет
| server_name site-b.com ---- ДА -> этот блок
+-------------------------------+
Как работает под капотом
Сначала Nginx фильтрует блоки по listen (адрес:порт). Если на этот порт подходит несколько server, он смотрит server_name и сопоставляет с заголовком Host. Порядок сопоставления: точное имя, затем маска вида *.example.com, затем маска вида www.example.*, затем регулярные выражения. Если ничего не совпало, используется default_server — блок, помеченный listen 80 default_server;, а если такого нет — первый по порядку. Поэтому «левые» запросы по IP без known-домена попадают именно в default_server.
Частые ошибки
- Нет default_server для «мусорных» запросов. Боты ходят по голому IP с любым Host; без явного default_server они попадут в первый попавшийся сайт. Заведи «заглушку», отдающую 444.
- Опечатка в
server_name. Тогда запрос молча уедет в default_server, и ты будешь видеть «не тот» сайт. - Забыть
wwwили наоборот. Перечисли все варианты или сделай редирект с одного на другой.
Best practices
- Заведи явный
default_serverсоreturn 444;для неизвестных Host — это закрывает целый класс проблем и сканеров. - Один сайт = один файл конфигурации (см. предыдущий урок).
- Канонизируй домен: выбери
example.comилиwww.example.comи редиректь второй на первый для SEO.
Канонизация домена и редиректы
Один из самых частых сценариев виртуальных хостов — приведение всех вариантов адреса к одному каноническому. Сайт доступен как example.com, www.example.com, по http и по https — это четыре разных URL для одной страницы, что плохо и для пользователей, и для поисковиков (дублирование контента размывает SEO). Решение: выбрать одну каноническую форму и редиректить на неё все остальные отдельными server-блоками с return 301.
Вот типичная связка: один server слушает порт 80 и редиректит на https; другой ловит www-вариант и редиректит на основной домен; и только третий, основной, реально обслуживает сайт. Такой подход чище, чем нагромождение if внутри одного блока — Nginx-сообщество даже придумало присказку «if is evil», потому что if в location ведёт себя неинтуитивно. Отдельные server-блоки с return работают быстрее и понятнее. И не забывай про default_server со return 444; (особый код Nginx, который просто закрывает соединение без ответа) — он отсекает ботов, стучащихся по голому IP с произвольным Host. Эти несколько блоков-«стражей» решают целый класс типовых проблем продакшена раз и навсегда.
Итоги
Виртуальные хосты — это блоки server, различаемые по listen (порт) и server_name (домен). Nginx выбирает блок по заголовку Host, а непонятные запросы отправляет в default_server. Это позволяет держать множество сайтов на одной машине. Дальше — глубокое погружение в раздачу статики и магию директивы location.