<HTML><BODY><p>Доброго дня сообществу! Прошу совета по проблеме.</p><p>Собственно, редирект с www на https без-www<br><br>server {<br>    #1 http to https without www<br>    listen 1.2.3.4:80;<br>    server_name www.test.com test.com;<br>    rewrite ^ https://test.com$request_uri? permanent;<br>}<br><br>server {<br>    #2 https with www to https without www<br>    listen 1.2.3.4:443 ssl;<br>    server_name www.test.com;<br>    rewrite ^ https://test.com$request_uri? permanent;<br>}<br><br>server {<br>    #3 https without www<br>    listen 1.2.3.4:443 ssl;<br>    server_name test.com;<br>    ...<br>}<br><br>Насколько я понял из документации (http://nginx.org/ru/docs/http/ngx_http_core_module.html#var_host), переменная $host принимает значения "в порядке приоритета: имя хоста из строки запроса, или имя хоста из поля Host заголовка запроса, или имя сервера, соответствующего запросу"<br><br>Судя по логам, это не совсем так.<br>По крайней мере, в моем случае (nginx/1.10.2), переменная $host получает имя хоста из строки запроса только если не указано поле host заголовка. Т.е. обрабатывается ситуация с HTTP/1.0, без $http_host в заголовке. Но если в заголовке задать какое-то (любое) значение $http_host, это же значение получает и $host.<br><br>Далее (http://nginx.org/ru/docs/http/request_processing.html): nginx "сопоставляет значение поля Host заголовка запроса с директивами server_name в блоках server, которые соответствуют IP-адресу и порту". Т.е. все-таки $http_host. А туда можно прописать что угодно.<br>Я не рассматриваю сейчас ситуацию, когда в $http_host прописано имя, не совпадающее с перечисленными в server_name. Это все благополучно фильтруется и отправляется на 444. Также, я не рассматриваю браузеры, которые отправляют правильный $http_host и получают правильные редиректы.<br><br>Вот такой случай:<br>curl -ILH 'Host: www.test.com' https://test.com<br><br>Если бы переменная $host получила значение в порядке приоритета, оно было бы test.com (имя хоста из строки запроса). Тогда можно было бы реализовать такой костыль, как фильтрация по условию "$host не равно $http_host". Но в запросе присутствует заголовок host, и обе переменные $host и $http_host получают одно и то же значение www.test.com , отфильтровать невозможно.<br>Имя www.test.com перечислено в server_name, в итоге такой запрос успешно проходит фильтрацию. После сопоставления значения $http_host с server_name, nginx отправляет запрос в секцию 2, откуда возвращается 301 и новый location https://test.com , т.е. на выходе получаем тот же самый запрос (curl -ILH 'Host: www.test.com' https://test.com) и, естесвенно, зацикливание на второй секции:<br><br>curl -ILH 'Host: www.test.com' https://test.com<br>HTTP/1.1 301 Moved Permanently<br>..........<br>Location: https://test.com/<br><br>HTTP/1.1 301 Moved Permanently<br>..........<br>Location: https://test.com/<br><br>..........<br><br>Это баг или фича? Или я что-то делаю не так? Как это побороть?<br>Спасибо.<br>--</p></BODY></HTML>