UMGUM.COM 

Nginx + no "Host" ( Обработка Nginx запросов без указания параметра "Host". )

29 января 2013  (обновлено 31 января 2015)

Эта публикация отнесена в архив. Она неактуальна.

OS: Linux Debian Lenny/Squeeze/Wheezy.
Application: Nginx.

Вероятно читатель этой заметки сталкивался с особенностями настройки web-серверов (Nginx, Apache), когда на обращения к серверу прямо по IP-адресу, без указания доменного имени, выдавался первый описанный в конфигурации сервера сайт, что не совсем соответствовало намерениям владельца ресурса.

Это нормальное поведение Nginx (да и Apache тоже - но здесь не о нём), который определяя, какому виртуальному web-серверу следует направить запрос, проверяет только поле "Host" заголовка запроса. Если его значение не соответствует ни одному из имён виртуальных web-серверов или в заголовке запроса нет этого поля вовсе, Nginx направит запрос в виртуальный web-сервер "по умолчанию" для этого порта, которым, если этого явно не обозначено, является первый упомянутый в конфигурационных файлах. Определение "первый упомянутый" нечёткое и на практике не всегда срабатывающее ожидаемым образом; избежать его использования можно явно определив какой-либо виртуальный web-сервер обработчиком запросов неприменимых к другим web-серверам.


Директива "listen" в описании виртуального web-сервера поддерживает параметр "default_server" (в версиях Nginx до 0.8.21 используется форма "default"), указывающая на особую роль этого виртуального web-сервера как обработчика всех не нашедших адресата запросов. Следует иметь в виду, что опция "default_server" задаёт свойства слушающего порта (сочетания IP адреса и IP-порта, который прослушивает Nginx), а не виртуального web-сервера, обслуживаемого Nginx; иначе говоря, мы указываем, что этот виртуальный web-сервер является обработчиком "по умолчанию" для какого-то определённого сетевого интерфейса, в то время как другому интерфейсу может быть назначен иной обработчик. Впрочем, если настроить Nginx на прослушивание всех интерфейсов одновременно, то и виртуальный web-сервер "по умолчанию" может быть только один.

Ещё в Nginx имеется возможность указать "пустое" имя сервера (начиная с Nginx версии 0.7.11). В документации указано, что это позволяет обрабатывать запросы без поля "Host" заголовка запроса в целевом виртуальном web-сервере. Для пущей эффективности, можно использовать и этот функционал.

Создаём для Nginx конфигурацию виртуального web-сервера, которая будет служить нам для перехвата запросов по IP-адресу без указания параметра "Host" и перенаправления таковых на заданное доменное имя "example.net":

# touch /etc/nginx/sites-available/no-host

server {
  listen      *:80 default_server;
  server_name localhost "";
  rewrite     ^(.*)$ http://example.net/ permanent;
}

server {
  listen      *:443 default_server;
  server_name localhost "";
  ....
  # Блок описания параметров установления SSL-сессии (помним, что защищённое соединение устанавливается до пересылки заголовков HTTP-запроса, потому оно должно состоятся даже только для того, чтобы сразу после этого быть сброшенным)
  ....
  rewrite     ^(.*)$ https://example.net/ permanent;
}

Здесь мы создали виртуальный web-сервер, обслуживающий доменное имя "localhost" (некому просматривать сайт прямо с сервера), прибавив к нему обслуживание "пустого" имени (эквиваленту запроса без параметра "Host") и объявив в придачу этот виртуальный web-сервер обработчиком запросов "по умолчанию" для всех сетевых интерфейсов сервера.

Обращаю внимание на нюанс настройки: просто "пустое" имя как опция параметра "server_name" у меня не применялось, требовалось указывать его в дополнение к какому-нибудь явному имени сервера, вроде "localhost".

Активируем конфигурацию символической ссылкой и даём Nginx команду применить её:

# ln -s /etc/nginx/sites-available/no-host /etc/nginx/sites-enabled/no-host
# /etc/init.d/nginx reload

На самом деле перенаправление всех нецелевых запросов на реальный web-сервер не всегда хорошая идея. С одной стороны это вроде как повышает доступность ресурса, а с другой стороны даёт возможность загрузить сервер бессмысленной работой, обрабатывая трафик генерируемый разного рода "ботами" и "сканерами". Я предпочитаю не перенаправлять нецелевые запросы, а отлавливать их и не отвечать на них вообще.

Nginx может прерывать обработку соединения, закрывая его без передачи клиенту заголовка ответа. Скорректируем конфигурацию, указав отдавать в ответ на запрос код "444" (который на самом деле не "отдаётся", а служит модификатором нестандартного поведения Nginx):

server {
  listen      *:80 default_server;
  server_name localhost "";
  return      444;
}

Теперь при запросе ресурса по IP-адресу соединение будет прерываться без ответа. В некоторых случаях браузеры могут проинформировать клиента о необычном поведении сервера следующим образом:

Zero Sized Reply: application did not receive any data for this request.

Материалы, используемые в работе:



Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )