У вас есть виртуальный хостинг (shared hosting), и часть клиентов получает контент не со своего ServerName, а с общего. Почему это происходит?

«У вас есть виртуальный хостинг (shared hosting), и часть клиентов получает контент не со своего ServerName, а с общего. Почему это происходит?» — вопрос из категории Веб-серверы и балансировка, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Эта проблема возникает из-за конфигурации виртуальных хостов (vhost) на веб-сервере. Когда входящий HTTP-запрос приходит, сервер пытается сопоставить заголовок Host с директивой ServerName или ServerAlias в конфигурациях виртуальных хостов.

Основная причина: Если запрос не соответствует ни одному явно объявленному ServerName/ServerAlias, сервер использует первый виртуальный хост, объявленный в конфигурации, в качестве хоста по умолчанию (default vhost). Этот хост и отдает контент.

Пример проблемной конфигурации Apache:

# Первый виртуальный хост в конфиге - становится default
<VirtualHost *:80>
    ServerName default.example.com
    DocumentRoot /var/www/default
</VirtualHost>

<VirtualHost *:80>
    # У этого хоста НЕТ директивы ServerName!
    # Запросы к client1.example.com не будут ему соответствовать.
    DocumentRoot /var/www/client1
</VirtualHost>

<VirtualHost *:80>
    ServerName client2.example.com
    DocumentRoot /var/www/client2
</VirtualHost>

В этом случае запрос к client1.example.com не найдет совпадения и будет обслужен первым vhost (default.example.com).

Решение:

  1. Убедитесь, что у каждого виртуального хоста есть корректная директива ServerName.
  2. Создайте явный, строго контролируемый виртуальный хост по умолчанию, который будет обрабатывать все несоответствующие запросы (например, возвращая ошибку 444 в nginx или перенаправляя на страницу-заглушку).

Пример для Nginx:

# Явный default server, блокирующий неправильные запросы
server {
    listen 80 default_server;
    server_name _;
    return 444;
}

# Корректные виртуальные хосты
server {
    listen 80;
    server_name client1.example.com;
    root /var/www/client1;
}

server {
    listen 80;
    server_name client2.example.com;
    root /var/www/client2;
}