Вопрос или проблема
Я не большой специалист в администрировании 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
сортируется на основе приоритетов и может не замещать как запланировано.
Применение
-
Убедитесь в правильности имен заголовков: Убедитесь, что вы используете правильные названия заголовков. Как правильно было подмечено в дополнительной секции, заголовки
X-Forwarded-*
должны быть использованы вместоX-Forward-*
. -
Уточните директивы
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;
}
Обратите внимание, что мы используем /.*
для учета всех путей, и добавляем путевой префикс прямо перед подстановочной переменной.
-
Проверьте результаты конфигурации: После внесения изменений рекомендуется проверить конфигурацию Nginx через команду
nginx -t
для обнаружения возможных ошибок. Затем перезагрузить Nginx:systemctl reload nginx
. -
Логи и отладка: Включите более подробный уровень регистрирования для Nginx, чтобы исследовать, как обрабатываются и возвращаются заголовки, с помощью директивы
error_log
с уровнемdebug
.
Такой подход должен помочь в корректной маршрутизации относительных путей, возвращаемых бэкендами, и их правильной интерпретации вашим шестидесятым сервером Nginx. Не забывайте тщательно тестировать изменения в конфигурациях в тестовом окружении перед применением на продакшн, чтобы минимизировать риск сбоев.