Nazwa zawiera słowo redirect, więc wkleja się ją do bloku location, gdy backend za VPN jest nieosiągalny. Nic się nie zmienia, a oczywisty wniosek jest taki, że dyrektywa jest zepsuta albo wymaga innej składni. W rzeczywistości stało się coś prostszego i mniej pochlebnego: proxy_redirect działa na odpowiedzi, która już wróciła, a w tym wdrożeniu żadne żądanie nigdy tak daleko nie dotarło.

Dwie dyrektywy, dwa momenty w jednym żądaniu

Żądanie HTTP przez odwrotne proxy przechodzi po kolei przez kilka decyzji, a obie dyrektywy leżą na przeciwnych końcach tej sekwencji. Jedna wybiera, dokąd trafi żądanie. Druga edytuje określone nagłówki w odpowiedzi, która wraca.

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

Ta kolejność to cała odpowiedź. Jeśli druga linia nigdy się nie wykona, bo pierwsza zawiodła, druga dyrektywa nie jest źle skonfigurowana, jest po prostu nieosiągalna. Ile by się drugiej linii nie przepisywało, odpowiedź, którą miała edytować, nie powstanie. Diagnozuj od pierwszej linii na zewnątrz, a mylące zachowanie sprowadza się do brakującej trasy albo odrzuconego połączenia.

Wybór upstreamu należy do proxy_pass

Załóżmy, że NGINX działa na publicznym hoście wejściowym i dociera do aplikacji pod 10.40.0.20:8080 przez swój VPN. Fragment, który wybiera tę aplikację, wygląda tak, wewnątrz istniejącego bloku server:

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

Użyj prawdziwego schematu, adresu i portu, i traktuj to jako fragment, a nie wdrożenie. Host wejściowy musi też utrzymywać trasę VPN, dozwoloną ścieżkę przekazywania i działający ruch powrotny do tej usługi, bo proxy, które na papierze dociera do adresu, nadal potrzebuje zgody jądra.

Dokumentacja modułu proxy trzyma wybór upstreamu osobno od przepisywania nagłówków odpowiedzi i zauważa, że wartość proxy_pass zawierająca URI zmienia sposób zastępowania pasującego prefiksu location. Dodawanie lub usuwanie elementów ścieżki bez sprawdzania URL-a, którego oczekuje aplikacja, to niezawodny sposób na uzyskanie 404, które wygląda jak błąd routingu.

proxy_redirect naprawia odpowiedzi, które ujawniają prywatny adres

Gdy ruch zacznie płynąć, backend może odpowiedzieć nagłówkiem Location wskazującym jego prywatny adres. Przeglądarka, która podąża za tym nagłówkiem, opuszcza publiczny punkt wejścia i próbuje dotrzeć do czegoś, czego nie potrafi rozwiązać. Celowo skonfigurowane przepisywanie odpowiedzi mapuje prywatny URL na publiczny:

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

Zastąp obie strony prawdziwymi wartościami. Zrozum także wąski zakres: pasujący tekst nagłówków Location i Refresh jest przepisywany, a URL-e osadzone w HTML, JavaScript albo pobranych plikach nie.

Jeśli aplikacja wszędzie buduje bezwzględne linki, trwałym rozwiązaniem jest jej własna konfiguracja zewnętrznego URL-a, a nie rosnąca lista reguł przepisywania na proxy. Dodawanie reguł, aż wynik wygląda dobrze, daje konfigurację, która zawodzi na pierwszej stronie, której nikt nie przetestował. Jedno poprawne ustawienie aplikacji zastępuje całą kolekcję.

Czego przepisanie nagłówka nie naprawi

Kilka sąsiednich problemów wygląda jak problemy z przekierowaniem i nimi nie jest. Nagłówek Host wysyłany do upstreamu może musieć pasować do wirtualnego hosta backendu. Upstream TLS może wymagać konkretnej nazwy serwera i weryfikacji certyfikatu, a przepisanie nagłówka odpowiedzi nie pomaga w żadnym z tych przypadków.

Zakres plików cookie i atrybuty domeny należą do aplikacji i jej konfiguracji. Proxy może przez cały dzień wyrzucać lub przepisywać nagłówki i wciąż wytworzyć sesję, która zawodzi przy drugim żądaniu, bo plik cookie wydano dla hosta, którego przeglądarka nigdy nie odwiedziła. Ta awaria wygląda na okresową, dlatego tak długo żyje w kolejce zgłoszeń. Odczytanie domeny pliku cookie zwykle kończy śledztwo w ciągu minuty.

Utrzymuj też uwierzytelnianie i wybór backendu w granicach zamierzonej aplikacji. Publiczne odwrotne proxy powinno udostępniać jedną aplikację przez VPN serwera, a nie stawać się uniwersalną bramą do każdego prywatnego adresu, do którego ten host dociera. Jedno ogólne location, które przekazuje wszystko, o co prosi wywołujący, zamienia jedną wystawioną usługę w mapę twojej prywatnej sieci. Nazwij upstream wprost i trzymaj go tam.

Testuj w kolejności, w jakiej podróżuje żądanie

Potwierdź po kolei trzy rzeczy: NGINX wybrał zamierzone location, zakończył żądanie do backendu, a przeglądarka poszła za każdym późniejszym przekierowaniem i wczytała zasoby podrzędne. Każdy krok ma własne linie logu, a czytanie ich po kolei zamienia niejasne 502 w konkretne ustalenie.

Potrzebne rozróżnienie to różnica między nieudanym połączeniem z upstreamem a przeglądarką wysłaną do nieosiągalnej prywatnej nazwy. Pierwsze pojawia się w logu błędów proxy; drugie pojawia się jako żądanie, które nigdy nie dociera, a przeglądarka skarży się na hosta, którego nie potrafi rozwiązać. Dwa różne problemy, dwa różne pliki, i tylko jeden z nich w ogóle dotyczy proxy_redirect.

Powiązane artykuły