Odwrotny serwer proxy Nginx + przepisywanie adresów URL

149

Nginx działa na porcie 80 i używam go do odwracania adresów URL proxy ze ścieżką /foodo portu w 3200ten sposób:

location /foo {
                proxy_pass http://localhost:3200;
                proxy_redirect     off;
                proxy_set_header   Host $host;
}

Działa to dobrze, ale mam aplikację na porcie 3200, dla której nie chcę, /fooaby wysyłano inicjał . To znaczy - kiedy uzyskuję dostęp http://localhost/foo/bar, chcę być tylko /barścieżką otrzymaną przez aplikację. Próbowałem więc dodać tę linię do powyższego bloku lokalizacji:

rewrite ^(.*)foo(.*)$ http://localhost:3200/$2 permanent;

Powoduje to przekierowanie 302 (zmiana adresu URL), ale chcę 301. Co powinienem zrobić?

jeffreyveon
źródło
Jeśli masz jakiś problem ze sprawą Grafana, powinieneś użyć następującego przepisu: docs.grafana.org/installation/behind_proxy/…
mohsen saeedi

Odpowiedzi:

169

Każde przekierowanie do localhost nie ma sensu ze zdalnego systemu (np. Przeglądarki internetowej klienta). Tak więc flagi przepisywania na stałe (301) lub przekierowania (302) nie są w twoim przypadku przydatne.

Spróbuj wykonać następującą konfigurację przy użyciu przezroczystej reguły przepisywania:

location  /foo {
  rewrite /foo/(.*) /$1  break;
  proxy_pass         http://localhost:3200;
  proxy_redirect     off;
  proxy_set_header   Host $host;
}

Służy curl -ido testowania przepisywania. Bardzo subtelna zmiana reguły może spowodować, że nginx wykona przekierowanie.

Jens Bradler
źródło
1
Ścieżka adresu URL wciąż zaczyna się od / foo w mojej aplikacji, gdy to robię ...
jeffreyveon
Musi być inny problem. Pomyślnie odtworzyłem ten scenariusz, zaledwie kilka minut temu. Oryginalny adres URL: http: // development / foo / testme / 1234 - REQUEST_URI skryptu PHP działającego na Apache podłączonym jako back-end proxy: '/ testme / 1234'
Jens Bradler
9
Wyrażenie regularne powinno prawdopodobnie być /foo(.*), w przeciwnym razie example.com/foonie zostanie dopasowane. (prawdopodobnie tego doświadczył jeffreyveon)
Benno
Ten rodzaj działa, ale moje ciało jest ustawione na proxy_set_body jest usuwane.
Justin Thomas
przepisać /(.*) /socket.io/ break; SAVE MY DAY FOR SOCKET.IO
user956584,
122

Proste dopasowanie prefiksu lokalizacji działa w tym przypadku bez użycia reguły przepisywania, o ile podasz identyfikator URI w dyrektywie proxy_pass:

location /foo {
  proxy_pass http://localhost:3200/;
}

Zwróć uwagę na dodatkowe /na końcu proxy_passdyrektywy. NGINX usunie dopasowany prefiks /fooi przekaże resztę do serwera zaplecza pod adresem URI /. W związku z tym http://myserver:80/foo/barwyśle ​​wiadomość do zaplecza o http://localhost:3200/bar.

Z dokumentów NGINX na proxy_pass :

Jeśli dyrektywa proxy_pass jest określona za pomocą identyfikatora URI, wówczas po przesłaniu żądania do serwera część znormalizowanego identyfikatora URI żądania pasującego do lokalizacji jest zastępowana identyfikatorem URI określonym w dyrektywie:

DanArl
źródło
12
Działa dla mnie, niż dodałem / to location / foo / {
Andrei N
Właśnie tego szukałem!
anbiniyar
6
To bardzo czyste rozwiązanie, wolałbym, aby była to kanoniczna odpowiedź na pytanie.
ralien
2
Trwało to zbyt długo, aby uświadomić sobie znaczenie zachowania lub usunięcia końcowego slash.
Parvez
5
//xyzJeśli tak zrobisz, dane te zostaną przekazane hostowi.
Archimedes Trajano,
60

Absolutnie najbardziej poprawny sposób i najlepsza praktyka są zwykle następujące:

location /foo/ {
    proxy_pass http://localhost:3200/; # note the trailing slash!
}

  • Zwróć uwagę na ogromne znaczenie końcowego ukośnikaproxy_pass , który automatycznie zmienia $urizmienną tak, aby /foo/przedni koniec był zgodny z /backendem. Nie ma potrzeby wyraźnej rewritedyrektywy.

  • Dodatkowo należy zauważyć, że The spływu /wlocation jest bardzo ważne, a także - bez niego, istnieje ryzyko konieczności dziwnie wyglądający adres URL na swojej stronie w pewnym momencie (np obróbki /fooenoprócz /foo/en).

    Dodatkowo, zakończenie /w locationz proxy_passzapewnia również pewne specjalne postępowanie , zgodnie z dokumentacją locationdyrektywy, aby skutecznie powodować również domniemane location = /foo {return 301 /foo/;}.

    Tak więc, definiując za locationpomocą ukośnika końcowego, jak powyżej, nie tylko upewniasz się, że takie URL-e bez sufiksu /fooennie będą prawidłowe, ale także, że /fooukośnik bez końcowego ukośnika będzie nadal działał.


Dokumentacja referencyjna:

cnst
źródło
Wygląda na to, że $argssą zgubione: http://frontend/foo?bar=bazzostaną przybliżone http://backend/. Zauważ, że argumenty nie są częścią
adresu
@Vanuan, jesteś tego pewien? Jestem pewien, $argsże nadal powinienem być odpowiednio obsługiwany, jeśli użyjesz powyższego kodu, ponieważ są one oddzielone $urii powinny zostać ponownie złożone, chyba że używasz w nich wyraźnych zmiennych proxy_pass.
cnst
@cnst Oh, rozumiem. Używam zmiennej hosta. To sprzeczne z intuicją.
Vanuan
1
@ArchimedesTrajano, jesteś niepoprawny, ponieważ istnieje specjalna obsługa /fooprzekierowywania do /foo/, więc jeśli nie robisz czegoś dziwnego na backendie, nawet /foożądania będą nadal działać z powyższym kodem. (To właściwie jest już część odpowiedzi, BTW.)
cnst
3
Chociaż to rozwiązanie „wydaje się” wygrywać na wszystkich tych forach, w samej odpowiedzi należy zauważyć, że Nginx będzie dekodować adres URL i przekazywać zdekodowany adres URL do serwera proxy. To rozwiązanie nie będzie działać, jeśli Twój adres URL zawiera części zakodowane w adresie URL.
kodowanie
1

próbować

location /foo {
    proxy_pass http://localhost:3200/;
    ....

lub

location ^~ /foo {
    proxy_pass http://localhost:3200/;
    ....
DerGeh
źródło
13
Ta odpowiedź byłaby dobra, gdybyś wyjaśnił, dlaczego należy ją skonfigurować jak wyżej.
masegaloeh
//xyzJeśli tak zrobisz, dane te zostaną przekazane hostowi.
Archimedes Trajano,
1

@Terabuck Przepraszamy za brak odpowiedzi.

Nie powinieneś używać localhost, ponieważ zależy to od faktu, że aplikacja działa na serwerze z plikiem hosts. host lokalny jest tylko domyślnym tłumaczeniem na 127.0.0.1. Nic nie wskazuje, że musisz mieć te pliki hostów. Po prostu jest to bardzo powszechne.

Posiadanie interfejsu sprzężenia zwrotnego jest kolejną powszechną rzeczą, na której można polegać, ale nadal jesteś zależny od interfejsu sprzężenia zwrotnego na stosie sieciowym. Rzadko zdarza się, aby nie mieć tych dwóch. Jeśli kiedykolwiek będziesz się tym martwić. Przynajmniej na unix / linux masz opcję gniazd. To wyeliminuje konieczność, aby stos sieciowy osiągnął hosta lokalnego. Zachowaj ostrożność przy takim podejściu, ponieważ istnieje kilka czynników, które pojawią się w systemie operacyjnym hosta. Takich jak liczba otwartych plików itp.

Cody Van Lith
źródło