В имени есть слово redirect, поэтому его вставляют в блок location, когда backend за VPN недоступен. Ничего не меняется, и очевидный вывод — директива сломана или требует другого синтаксиса. На самом деле произошло более простое и менее лестное: proxy_redirect работает с ответом, который уже вернулся, а в этом развёртывании ни один запрос туда не дошёл.

Две директивы, два момента в одном запросе

HTTP-запрос через обратный прокси по порядку проходит несколько решений, и две директивы стоят на противоположных концах этой последовательности. Одна выбирает, куда пойдёт запрос. Другая правит определённые заголовки в ответе, который возвращается.

DirectiveWhen it actsWhat it can change
proxy_passBefore any bytes leave the proxyWhich upstream receives the request
proxy_redirectAfter the upstream respondsMatching Location and Refresh text

Этот порядок и есть весь ответ. Если вторая строка никогда не выполняется, потому что первая не сработала, вторая директива не настроена неправильно — она просто недостижима. Сколько ни переписывай вторую строку, ответ, который она должна была править, не появится. Диагностируйте от первой строки наружу, и запутанное поведение сводится к отсутствующему маршруту или отклонённому соединению.

Выбор upstream относится к proxy_pass

Предположим, NGINX работает на публичном входном хосте и через свой VPN достигает приложения по 10.40.0.20:8080. Фрагмент, который выбирает это приложение, выглядит так, внутри существующего блока server:

location / {
    proxy_pass http://10.40.0.20:8080;
}

Используйте реальную схему, адрес и порт и относитесь к этому как к фрагменту, а не как к развёртыванию. Входной хост также должен держать маршрут VPN, разрешённый путь пересылки и рабочий обратный трафик к этой службе, потому что прокси, достигающий адреса на бумаге, всё равно нуждается в согласии ядра.

Справочник модуля proxy держит выбор upstream отдельно от перезаписи заголовков ответа и отмечает, что значение proxy_pass с URI меняет то, как заменяется соответствующий префикс location. Добавлять или убирать компоненты пути, не проверяя URL, который ожидает приложение, — надёжный способ получить 404, выглядящий как сбой маршрутизации.

proxy_redirect исправляет ответы, выдающие приватный адрес

Как только трафик пошёл, backend может ответить заголовком Location, в котором указан его приватный адрес. Браузер, следующий этому заголовку, покидает публичную точку входа и пытается достичь того, что не может разрешить. Намеренно настроенная перезапись ответа сопоставляет приватный URL с публичным:

proxy_redirect http://10.40.0.20:8080/ https://app.example.com/;

Замените обе стороны реальными значениями. Поймите и узкий охват: соответствующий текст заголовков Location и Refresh перезаписывается, а URL, встроенные в HTML, JavaScript или скачанные файлы, нет.

Если приложение строит абсолютные ссылки повсюду, долговечное решение — его собственная конфигурация внешнего URL, а не растущий список правил перезаписи на прокси. Добавление правил, пока вывод не станет выглядеть правильно, даёт конфигурацию, которая падает на первой странице, которую никто не проверял. Одна правильная настройка приложения заменяет весь набор.

Что перезапись заголовка не может исправить

Несколько соседних проблем выглядят как проблемы перенаправления, но ими не являются. Заголовок Host, отправляемый в upstream, может требовать соответствия виртуальному хосту backend. TLS upstream может требовать конкретного имени сервера и проверки сертификата, и перезапись заголовка ответа не помогает ни тому, ни другому.

Область действия cookie и атрибуты домена принадлежат приложению и его конфигурации. Прокси может целый день выбрасывать или перезаписывать заголовки и всё равно создать сессию, которая падает на втором запросе, потому что cookie выдан для хоста, который браузер никогда не посещал. Этот сбой выглядит периодическим, поэтому он так долго живёт в очереди заявок. Чтение домена cookie обычно завершает расследование за минуту.

Держите аутентификацию и выбор backend тоже ограниченными предполагаемым приложением. Публичный обратный прокси должен открывать одно приложение через VPN сервера, а не становиться универсальным шлюзом к каждому приватному адресу, который доступен этому хосту. Один общий location, который пересылает всё, что попросит вызывающий, превращает один открытый сервис в карту вашей приватной сети. Назовите upstream явно и держите его там.

Проверяйте в том порядке, в котором идёт запрос

Подтвердите три вещи по порядку: NGINX выбрал нужный location, завершил запрос к backend, а браузер последовал за любым последующим перенаправлением и загрузил подресурсы. У каждого шага свои строки лога, и чтение их по порядку превращает расплывчатую 502 в конкретную находку.

Нужное вам различие — между неудачным соединением с upstream и браузером, отправленным на недоступное приватное имя. Первое появляется в логе ошибок прокси; второе выглядит как запрос, который никогда не приходит, а браузер жалуется на хост, который не может разрешить. Две разные проблемы, два разных файла, и только одна из них вообще касается proxy_redirect.

Похожие статьи