Переадресация Nginx с относительными путями

Вопрос или проблема

Я не большой специалист в администрировании nginx, я просто разработчик. У меня есть два бэкенда, работающих в docker. Назову их

  • backend1:8080
  • backend2:8081

Также у меня есть Nginx, открывающий порт 443 с установленными сертификатами letsencrypt. Моя конфигурация Nginx (переменная среды FQDN это что-то вроде example.com)

upstream backend1 {
  server backend1:8080;
}

upstream backend2 {
  server backend2:8081;
}

server {
  listen 443 ssl;

  server_name ${FQDN} www.${FQDN};

  ssl_certificate /etc/letsencrypt/live/${FQDN}/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/${FQDN}/privkey.pem;
  ssl_session_cache shared:SSL:1m;
  ssl_session_timeout  5m;
  ssl_ciphers  HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers   on;

  if ($server_port = 80) { set $https_redirect 1; }
  if ($host ~ '^www\.') { set $https_redirect 1; }
  if ($https_redirect = 1) { return 301 https://${FQDN}$request_uri; }

  location /path1/ {

    proxy_pass http://backend1/;

    proxy_redirect ~^/(.*) $scheme://$http_host/path1/$1;

    proxy_http_version 1.1;

    proxy_pass_header Set-Cookie;
    proxy_pass_header Cookie;
    proxy_pass_header X-Forwarded-For;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forward-Proto http;
    proxy_set_header X-Nginx-Proxy true;
    add_header       X-Upstream      $upstream_addr;
  }

  location /path2/ {

    proxy_pass http://backend2/;

    proxy_redirect ~^/(.*) $scheme://$http_host/path2/$1;

    proxy_http_version 1.1;

    proxy_pass_header Set-Cookie;
    proxy_pass_header Cookie;
    proxy_pass_header X-Forwarded-For;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forward-Proto http;
    proxy_set_header X-Nginx-Proxy true;
    add_header       X-Upstream      $upstream_addr;
  }
}

Я хочу, чтобы если я запрашиваю https://exapmle.com/path1/, то Nginx должен обратиться к http://backend1:8080/ и вернуть мне ответ от этого сервера. Проблема в том, что backend1 (как и backend2) может ответить с 302 и перенаправить на какой-то путь, например /login. Nginx перенаправляет мой браузер на https://exapmle.com/login, но я хочу, чтобы он перенаправлял на https://exapmle.com/path1/login
Можете ли вы помочь мне и указать на ошибку, которую я сделал в своей конфигурации. Я просмотрел все похожие вопросы на SO и не нашел решения. Я также изучил документацию Nginx и также не нашел ответа.

У меня есть строка proxy_redirect ~^/(.*) $scheme://$http_host/path1/$1;, и я предполагаю, что она должна выполнять то, что я хочу.

Кстати, я не могу занять / локацию (создать конфигурацию для корневого пути) в моей конфигурации Nginx, так как она зарезервирована для другого бэкенд сервера. Заранее спасибо.

Возможно, это из-за неверно написанных заголовков X-Forwarded в вашей конфигурации. Должно быть X-Forwarded-* вместо X-Forward-*.

location /path1/ {

proxy_pass http://backend1/;

proxy_redirect default;
proxy_redirect / /path1/;
proxy_redirect  http://backend1/ https://exapmle.com/path1/;

proxy_http_version 1.1;

proxy_pass_header Set-Cookie;
proxy_pass_header Cookie;
proxy_pass_header X-Forwarded-For;

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forward-Proto http;
proxy_set_header X-Nginx-Proxy true;
add_header       X-Upstream      $upstream_addr;}

так в порядке.

Ответ или решение

Для решения проблемы конфигурации Nginx с использованием директивы proxy_redirect при работе с относительными путями, давайте подробно разберем вашу ситуацию.

Теория

Ваша задача заключается в правильной настройке обратного проксирования в Nginx для двух бэкендов, работающих на разных портах в Docker-контейнерах, и необходимости обработки перенаправлений, выполняемых этими бэкендами. В данный момент, когда ваша бэкенд-система (например, backend1) возвращает редирект на относительный путь, браузер перенаправляется на корневой маршрут, например, https://example.com/login, в то время как вы ожидаете https://example.com/path1/login.

Для достижения этого поведения необходимо правильно настроить директиву proxy_redirect, чтобы Nginx подменял ссылки в заголовках Location, возвращаемых бэкендами, добавляя нужный подкаталог.

Пример

Во-первых, посмотрим на вашу текущую конфигурацию:

location /path1/ {
    proxy_pass http://backend1/;
    proxy_redirect ~^/(.*) $scheme://$http_host/path1/$1;
    ...
}

Здесь директива proxy_redirect пытается взять любой ответ, начинающийся с /, и подставить https://example.com/path1/. Однако данная формулировка может не работать как ожидается из-за того, что proxy_redirect сортируется на основе приоритетов и может не замещать как запланировано.

Применение

  1. Убедитесь в правильности имен заголовков: Убедитесь, что вы используете правильные названия заголовков. Как правильно было подмечено в дополнительной секции, заголовки X-Forwarded-* должны быть использованы вместо X-Forward-*.

  2. Уточните директивы proxy_redirect: Вы можете попробовать настройки proxy_redirect, чтобы они соответствовали стандартным примерам, когда редиректы выполняются на подкаталоги.

Пример модификации конфигурации:

location /path1/ {
    proxy_pass http://backend1/;
    proxy_redirect ~^(/.*)$ $scheme://$http_host/path1$1;
    proxy_http_version 1.1;
    proxy_pass_header Set-Cookie;
    proxy_pass_header Cookie;
    proxy_pass_header X-Forwarded-For;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    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 https;
    proxy_set_header X-Nginx-Proxy true;
    add_header X-Upstream $upstream_addr;
}

Обратите внимание, что мы используем /.* для учета всех путей, и добавляем путевой префикс прямо перед подстановочной переменной.

  1. Проверьте результаты конфигурации: После внесения изменений рекомендуется проверить конфигурацию Nginx через команду nginx -t для обнаружения возможных ошибок. Затем перезагрузить Nginx: systemctl reload nginx.

  2. Логи и отладка: Включите более подробный уровень регистрирования для Nginx, чтобы исследовать, как обрабатываются и возвращаются заголовки, с помощью директивы error_log с уровнем debug.

Такой подход должен помочь в корректной маршрутизации относительных путей, возвращаемых бэкендами, и их правильной интерпретации вашим шестидесятым сервером Nginx. Не забывайте тщательно тестировать изменения в конфигурациях в тестовом окружении перед применением на продакшн, чтобы минимизировать риск сбоев.

Оцените материал
Добавить комментарий

Капча загружается...