
Виртуальные хосты Nginx для нескольких доменов
Настраиваем несколько сайтов в Nginx: отдельные server-блоки, default_server, server_name, тест через Host и --resolve, безопасное включение и откат.
Содержание
Несколько доменов могут указывать на один IP-адрес. Nginx различает их по имени, которое передаёт клиент, и для каждого выбирает свой блок server. Так сайты получают отдельные каталоги, журналы и правила, хотя используют один веб-сервер.
При настройке важно явно определить поведение для неизвестного имени. Иначе запрос, не совпавший ни с одним server_name, может показать первый настроенный сайт и раскрыть чужой проект на неожиданном домене.
Подготовьте карту доменов
До редактирования запишите для каждого сайта:
| Домен | Каталог | Тип | HTTPS |
|---|---|---|---|
example.com |
/var/www/example/current |
статика | отдельный сертификат |
docs.example.com |
/var/www/docs/current |
статика | отдельный сертификат |
Не копируйте эти имена как настоящую настройку. Замените домены и пути, проверьте DNS и владельцев каталогов.
Разделяйте production-файлы проектов. Общий корень с произвольными подпапками усложняет права, deploy и удаление. Веб-серверу обычно достаточно чтения, а пользователь публикации владеет релизами.
Создайте безопасный default server
Создайте отдельный блок, который принимает запросы с неизвестным Host на порту 80 и возвращает обычный 404. Роль сервера по умолчанию задаёт параметр default_server в listen:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 404;
}
default_server относится к адресу и порту. Строка server_name _ не создаёт магического wildcard, а служит заведомо неподходящим обычным именем. Если IPv6 на сервере не настроен, не добавляйте listen [::] без проверки.
В некоторых конфигурациях неизвестные запросы закрывают нестандартным кодом Nginx. Обычный 404 проще для обучения и наблюдения. Выбор зависит от политики сервера.
Настройте первый домен
В отдельном файле сайта укажите его имена, каталог опубликованных файлов и журналы. Следующий пример обслуживает example.com и www.example.com как один проект:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example/current;
index index.html;
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log;
location / {
try_files $uri $uri/ =404;
}
}
Точные имена перечислены явно. root указывает только на опубликованный релиз, не на репозиторий или домашний каталог. Проверка try_files не передаёт неизвестный URI другому приложению.
Перед reload убедитесь, что Nginx может пройти путь и прочитать файл:
namei -l /var/www/example/current/index.html
sudo -u www-data test -r /var/www/example/current/index.html
Имя worker-пользователя уточните по действующей конфигурации; оно не универсально.
Отделите второй сайт
Для docs.example.com создайте другой server-блок с собственным каталогом и журналами. Такое разделение позволяет обновлять и отключать проекты независимо:
server {
listen 80;
listen [::]:80;
server_name docs.example.com;
root /var/www/docs/current;
index index.html;
access_log /var/log/nginx/docs.access.log;
error_log /var/log/nginx/docs.error.log;
location / {
try_files $uri $uri/ =404;
}
}
Не смешивайте домены разных проектов в одном server_name, если у них разные релизы, политика TLS или журналы. Отдельный блок упрощает откат и диагностику.
На Debian/Ubuntu файл часто создают в sites-available, а в sites-enabled помещают символическую ссылку. Это соглашение пакета, а не обязательное правило самого Nginx:
sudo ln -s /etc/nginx/sites-available/example.conf /etc/nginx/sites-enabled/example.conf
Сначала убедитесь, что путь включения действительно подключён из nginx.conf, а ссылка с таким именем не существует.
Проверьте конфликты в полном дереве
sudo nginx -t
sudo nginx -T 2>&1 | less
Найдите все listen, server_name и default_server. Предупреждение о конфликтующем имени означает, что часть настройки может игнорироваться. Не пытайтесь решить конфликт перестановкой файлов: одно имя должно иметь понятного владельца на конкретном адресе и порту.
Избегайте широких регулярных server_name, пока точных имён достаточно. Wildcard и regex имеют собственный приоритет и могут принять лишний домен.
Тестируйте до изменения DNS
Ниже используется зарезервированный для документации адрес 203.0.113.10; замените его фактическим IP проверяемого сервера.
Для HTTP:
curl -i -H 'Host: example.com' http://203.0.113.10/
curl -i -H 'Host: docs.example.com' http://203.0.113.10/
curl -i -H 'Host: unknown.invalid' http://203.0.113.10/
Третий запрос должен показать поведение default server, а два первых — разные маркеры сайтов. Не используйте только одинаковые шаблоны страниц: разместите в тестовых index.html различимый текст.
Для HTTPS корректно передайте и SNI, и Host:
curl -i --resolve example.com:443:203.0.113.10 https://example.com/
--resolve меняет разрешение имени для этого запроса. Публичный DNS остаётся прежним. Сертификат должен соответствовать домену; постоянный -k скрыл бы важную ошибку.
Добавьте HTTPS без дублирования логики
Сначала получите и проверьте сертификат штатным способом вашего центра сертификации. Не придумывайте путь к ключу и не копируйте чужой конфиг. В HTTPS server указываются listen 443 ssl, точные имена, сертификат и ключ.
HTTP-блок обычно либо обслуживает проверку центра сертификации, либо перенаправляет известные домены на HTTPS:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
Такой редирект канонизирует www на основной домен. Сначала проверьте, что это соответствует выбранной структуре URL и сертификат уже работает. Не добавляйте HSTS до устойчивой работы HTTPS на всех нужных поддоменах.
Перед добавлением нескольких виртуальных хостов настройте один домен, TLS и внешний запрос по базовой схеме Nginx.
Разделите журналы и наблюдение
Отдельный access log помогает понять трафик конкретного домена. Error log может быть общим или отдельным, но его расположение должно быть предсказуемым. После reload выполните:
systemctl status nginx --no-pager
sudo tail -n 30 /var/log/nginx/example.error.log
Затем проверьте главную, вложенный URL, отсутствующую страницу и статический ресурс. Код 200 у одного адреса ещё не доказывает, что выбран правильный root.
Откат
Если новый сайт мешает существующему, отключите только его include или ссылку, верните предыдущий default server при необходимости, затем выполните:
sudo nginx -t
sudo systemctl reload nginx
Не удаляйте каталог сайта и сертификат одновременно с отключением: сохраните артефакты до подтверждения отката. Повторите запросы ко всем прежним доменам и неизвестному Host.
После выбора виртуального хоста запрос обрабатывают правила location, root, alias и try_files. Если Nginx выбирает неожиданный блок, восстановите весь путь HTTP-запроса по журналу и активной конфигурации.
Первоисточники
- Server names в Nginx — формы имён, приоритет и стадии выбора virtual server.
- Как Nginx обрабатывает запрос —
listen,default_server, Host и маршрутизация.
Самопроверка
Проверьте, что материал усвоен
Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.
Разбираем коротко
Частые вопросы
Сколько сайтов можно обслуживать одним Nginx?
Жёсткого универсального числа нет: один экземпляр может обслуживать много виртуальных серверов, если хватает ресурсов и конфигурация остаётся управляемой. Ограничения определяют трафик, TLS, журналы, файлы и приложения.
Нужно ли каждому домену назначать отдельный IP-адрес?
Обычно нет. Несколько доменов могут указывать на один IP, а Nginx выбирает server-блок по имени запроса. Отдельный адрес нужен только для специальных сетевых или организационных требований.
Почему новый домен показывает уже существующий сайт?
Чаще всего запрос попал в default_server, потому что нужный server-блок не подключён, server_name не совпал или DNS ведёт на другой сервер. Проверьте nginx -T и запрос с явным Host или --resolve.


