Вопрос или проблема
Я пытаюсь настроить обратный прокси nginx в контейнере docker на машине с Windows для разработки. Это должно отражать, как связаны сервисы на производстве.
В настоящее время я сталкиваюсь с проблемой, когда при попытке маршрутизации на другую машину в сети по IP-адресу, я не могу сделать это, так как это приводит к зацикленной запросу, пока nginx не выдаст “400 header or cookie too large”, так как заголовок X-Forwarded-For становится слишком большим, похоже.
Когда я выполняю команду curl локально на своей хостовой машине:
curl -v -H "Host: subdomain1.example.com" http://192.168.1.10
Я получаю ожидаемый ответ, который является ответом с сайта IIS. Но при выполнении команды в контейнере docker я получаю ответ 400 от nginx.
Я думал, что проблема в том, что DNS разрешает subdomain1.example.com на себя. Поскольку на роутере есть локальный DNS, который отображает subdomain1.example.com на IP-адрес хостовой машины Windows. Но даже когда я настраиваю пользовательский резолвер (который является контейнером dnsmasq, работающим на хостовой машине Windows – проверено с помощью nslookup), я получаю ту же ошибку. Я пытался установить DNS контейнера docker с помощью команды --dns=192.168.1.11
, а также установить --add-host=subdomain1.example.com:192.168.1.10
. Но что бы я ни делал, это, похоже, всегда приводит к рекурсивной петле. Проблема возникает только при установке proxy_set_header Host "subdomain1.example.com"
. Как только я его убираю, маршрутизация работает, но на сайт по умолчанию в IIS, что мне не нужно. Мне нужно, чтобы заголовок хоста совпадал с именем сервера nginx, чтобы правильное привязка могла быть обнаружена в IIS и направлена на правильный сайт.
Подхватывает ли nginx, что заголовок хоста совпадает с именем сервера, и пытается обработать запрос самостоятельно? Если да, то как мне это прекратить, но при этом сохранить заголовок хоста, чтобы он мог использоваться в IIS? Я не могу изменить поддомен заголовка хоста, так как сайт приложения выдаст ошибку POST CORS. Например, если я использую subdomain1proxy.example.com
и привяжу его к тому же сайту – это не подходит из-за проблемы с CORS. Он должен совпадать с хостом запроса.
Как я могу этого добиться?
Вот мой текущий конфигурационный файл:
upstream iis_server {
server 192.168.1.10:80;
}
upstream next_server {
server host.docker.internal:3000;
}
upstream api_server {
server host.docker.internal:7071;
}
upstream image_server {
server host.docker.internal:7072;
}
server {
listen 80;
server_name subdomain1.example.com;
location ~ ^/(?<dest>(one|two|three).*) {
resolver 192.168.1.11 ipv6=off;
proxy_pass http://iis_server;
proxy_set_header Host "subdomain1.example.com";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://next_server/;
proxy_redirect off;
}
}
server {
listen 80;
server_name subdomain2.example.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://api_server/;
proxy_redirect off;
}
}
server {
listen 80;
server_name subdomain3.example.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://image_server/;
proxy_redirect off;
}
}
Ответ или решение
Настройка обратного прокси-сервера Nginx в контейнере Docker может быть непростой задачей, особенно когда вы сталкиваетесь с проблемами, такими как циклические перенаправления или ошибки "400 header or cookie too large". В данной ситуации возникает проблема, когда попытка проксировать запросы из Docker-контейнера с установленным заголовком proxy_set_header Host
приводит к рекурсивному циклу и, в конечном итоге, к ошибке "400".
Теория
Основная задача обратного прокси заключается в том, чтобы направлять входящие HTTP-запросы к соответствующим серверам на основе выбранных условий конфигурации. Заголовок Host
играет важную роль в маршрутизации запросов, особенно если на конечном сервере, таком как IIS, настроено несколько сайтов, и они идентифицируются именно по этому заголовку.
Циклы в HTTP-запросах обычно возникают из-за некорректной настройки правил перенаправления или проксирования, где прокси-сервер может пытаться обработать запросы сам, перенаправляя их обратно на себя.
Пример
Согласно представленному конфигурационному файлу Nginx, наблюдается следующее:
-
В секции, которая отвечает за проксирование к IIS (
upstream iis_server
), вы устанавливаетеproxy_set_header Host "subdomain1.example.com"
. Это действие говорит Nginx отправлять в виде заголовкаHost
измененное значение, отличное от исходного. -
В конфигурации есть правило для
server_name subdomain1.example.com
, что означает, что Nginx ожидает входящих запросов на этот точный хост. Установка заголовкаHost
идентичнымserver_name
может привести к тому, что Nginx начнет рассматривать эти запросы как предназначенные для себя и попытаться их обработать, что потенциально инициирует циклический переход. -
Разрешение DNS зацикливается, если нет программного разделения для маршрутизации данных запросов, что может вызывать ошибку.
Применение
Для устранения проблемы с рекурсией и коррекцией проксирования попробуйте следующие действия:
-
Измените резолюцию: Перепроверьте и при необходимости скорректируйте записи DNS, чтобы убедиться, что любые ссылки на
subdomain1.example.com
разрешаются верно и не ведут обратно к конфигурации основного сервера Nginx. -
Тонкая настройка проксирования: Попробуйте изменить или исключить
proxy_set_header Host
, вместо этого настройте IIS так, чтобы он мог принимать и интерпретировать запросы без необходимости в изменении заголовкаHost
. Если это невозможно, убедитесь, что прокси передает запросы в уникальный виртуальный хост на IIS. -
Временный тест без заголовка: Можно на уровне теста временно убрать строчку
proxy_set_header Host
и проверить, как запросы маршрутизируются. Если маршрутизация работает надежно, проблема точно кроется именно в заголовках и необходимости их пересылки. -
Логирование и отладка: Включите большее количество логирования для Nginx и Docker, чтобы лучше понять, где осуществляется процесс перенаправления и точную точку возникновения зацикливания.
-
Обновление конфигурации для уникальности маршрутизации: Разделите конфигурации / цели маршрутизации, чтобы избежать коллизий. Это может включать установку альтернативных портов или дальнейшие модификации конфигурации IIS для уникального идентификатора бэкенда.
-
Консультация с документацией Nginx и IIS: Просмотрите официальную документацию для обоих систем относительно настройки прокси и обработки заголовков, чтобы не упустить каких-либо специфических рекомендаций.
Заключение
Для успеха в решении подобной проблемы требуется комплексный подход к настройке сетевого окружения, понимание ролей заголовков HTTP и конфигурации серверов приложений. Важно понимать, что во многих случаях проблемы, связанные с заголовками и проксированием, требуют углубленной отладки и тестирования различных подходов, прежде чем будет найдено наиболее устойчивое решение.