Jak usunąć ścieżkę za pomocą nginx proxy_pass

77

Mam uruchomioną aplikację internetową http://example.com/i chcę „zamontować” inną aplikację na osobnym serwerze http://example.com/en. proxy_passWydaje się, że serwery nadrzędne działają, ale w przypadku jednego problemu:

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location /en {
    proxy_pass http://luscious;
  }
}

Podczas otwierania example.com/enmoja poprzednia aplikacja powraca 404 not found /en. Ma to sens, ponieważ górny bieg nie ma ścieżki /en.

Czy proxy_pathto właściwe rozwiązanie? Czy powinienem przepisać „upstream”, aby /enzamiast tego nasłuchiwał , ponieważ jest to ścieżka root? Czy też istnieje dyrektywa, która pozwala mi przepisać ścieżkę przekazywaną do góry?

berkes
źródło

Odpowiedzi:

133

Jest to prawdopodobnie najbardziej efektywny sposób robienia tego, co chcesz, bez użycia wyrażeń regularnych:

location = /en {
    return 302 /en/;
}
location /en/ {
    proxy_pass http://luscious/;  # note the trailing slash here, it matters!
}
cnst
źródło
1
O ile mi wiadomo, ostatnia część nadal podawałaby „/ en” jako ścieżkę do proxy, prawda?
berkes,
15
@berkes, nie, nie zrobi tego - końcowy ukośnik proxy_passrobi różnicę. Ponadto, ta odpowiedź jest bardziej poprawna niż ta, którą wymyśliłeś, ponieważ zapewnia również, że proxy_redirectpozostanie w default, więc możesz nadal używać 302et al w swoim backendie i mieć poprawne działanie wszędzie.
cnst
4
Ach, brakowało mi końcowego slash :(
Vanuan
3
AAARGH! TRAILING SLASH!
barrymac
4
3 godziny poszukiwań i tak ... To był ostatni slash. Dzięki stary!
Lucas P.,
12

Chciałbym odpowiedzieć na nową odpowiedź opartą na wyrażeniach regularnych, która zyskuje na popularności.

location ~ ^/en(/?)(.*)$ {  # OOPS!
  proxy_pass http://luscious/$2$is_args$args;  # OOPS!
}

Rozwiązanie na pierwszy rzut oka może wydawać się bardziej urocze, ale jest błędne z wielu powodów.

  • Powyższy regex pasowałby do identyfikatora uri żądania /enjoy, przekierowując go do /joyupstream. Czy to naprawdę jest zamierzone?

  • Prośba o /ennie spowoduje żadnych przekierowań, bezpośrednio obsługujących /z nadrzędnego (prawie tak, jakby prośba /en/została wysłana zamiast, ale nie do końca). Jeśli używasz względnych identyfikatorów URI na stronie głównej w górę (w innym przypadku, dlaczego nie miałbyś /en/prefiksu bezpośrednio w obrębie wcześniejszych identyfikatorów?), Np. src="style.css"(Która może odnosić się url("menu.png")na przykład do określonego języka ), wtedy przeglądarka zażąda jak /style.csszamiast /en/style.css. (Lub nawet jeśli wszędzie używasz bezwzględnych identyfikatorów URI, a jeśli ktoś odwołuje się do nieznanego zasobu częściowo opcjonalnego?) Ups, witryna nagle może nie działać, ale tylko czasami lub w skrajnych przypadkach.

  • Zgodnie z moją wcześniejszą radą dotyczącą innego pytania, które zostało już wspomniane przez własną odpowiedź PO , użycie wyrażeń regularnych uniemożliwia, by proxy_redirectdyrektywa miała domyślną wartość default, offzamiast tego ją obniżyła . Oznacza to, że jeśli poprzedni użytkownik odpowie, Location: http://127.0.0.1:8080/en/dir/kiedy /en/dirzostanie złożone żądanie , wówczas zobaczy to klient, co oczywiście nie będzie działać poprawnie. (Co byłoby szczególnie ironiczne w przypadku /enżądania, które w pierwszej kolejności zachęca do użycia wyrażenia regularnego, jednak ta konkretna implementacja cierpi z powodu innego problemu, jak już wspomniano powyżej.) Ponadto, jeśli już używaszupstreamdyrektywy, to może stać się wyjątkowo brzydkie, jeśli po prostu spróbujesz użyć niestandardowego, szczególnie jeśli masz więcej niż jeden serwer nadrzędny - w jaki sposób masz osobny proxy_redirectdla każdego z nich? Możesz również użyć wyrażeń regularnych proxy_redirect, może nawet w celu dopasowania do dowolnego hosta, ale co wtedy, jeśli zdecydujesz się na przekierowanie między domenami w przyszłości?

Aby spróbować rozwiązać niektóre z powyższych punktów za pomocą pojedynczej lokalizacji opartej na wyrażeniach regularnych, moglibyśmy wykonać następujące czynności (zauważ, że w celu proxy_passuproszczenia również musieliśmy usunąć odwołanie do serwera z upstreamdyrektywy opartej na wyrażeniach regularnych proxy_redirect):

location ~ ^/en/?((?<=/).*)?$ {
  location = /en { return 302 /en/; }
  proxy_pass http://127.0.0.1:8080/$1$is_args$args;
  proxy_redirect http://127.0.0.1:8080/ /en/;
}

Tak więc, jeśli zapytasz mnie, oryginalne rozwiązanie z dwoma rodzeństwami na najwyższym poziomie nadal byłoby lepszym pomysłem niż wykopanie się w króliczej nucie, zamiast tego wybranie trasy wyrażenia regularnego.

cnst
źródło
Powoduje to wyjątek:nginx: [emerg] location "/en" is outside location "^/en/?((?<=/).*
Athlan
1
@Athlan, to dlatego, że tak naprawdę nie powinieneś tego używać! Jeśli nadal chcesz, możesz umieścić tę lokalizację poza wyrażeniem regularnym.
cnst
umieszczanie lokalizacji = / pl na zewnątrz działa naprawdę dobrze! dzięki
Sebastian Webber
7

Znalazłem odpowiedź na stackoverflow :

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location ~ ^/en(/?)(.*) {
    proxy_pass http://luscious/$2;
  }
}

Zasadniczo: przekazywanie wyrażenia regularnego do lokalizacji i przekazywanie odnośnika zwrotnego do adresu URL proxy_pass.

berkes
źródło
Myślę, że „proxy_pass luscious / $ ;” powinno być „proxy_pass luscious / $ 2
Zafer
1
@Zafer ma rację, powyższa odpowiedź dała mi błąd
franck
Zmieniłem odpowiedź, ale nie mam pod ręką serwera, w którym mógłbym spróbować, bankomat, więc nie jest to zweryfikowane.
berkes
0

Księgowość do dokumentów Nginx

Aby przekazać żądanie do serwera proxy HTTP, dyrektywa proxy_pass jest określona w lokalizacji. Na przykład:

location /some/path/ {
    proxy_pass http://www.example.com/link/;
}

Ta przykładowa konfiguracja powoduje przekazanie wszystkich żądań przetworzonych w tej lokalizacji do serwera proxy pod określonym adresem. Ten adres można podać jako nazwę domeny lub adres IP. Adres może również zawierać port:

location ~ \.php {
    proxy_pass http://127.0.0.1:8000;
}

Zauważ, że w pierwszym przykładzie powyżej po adresie serwera proxy znajduje się identyfikator URI, / link /. Jeśli identyfikator URI jest podany wraz z adresem, zastępuje on część identyfikatora URI żądania, który pasuje do parametru lokalizacji. Na przykład tutaj żądanie z /some/path/page.html URI będzie proxy do http://www.example.com/link/page.html . Jeśli adres jest określony bez identyfikatora URI lub nie jest możliwe określenie części identyfikatora URI, która ma zostać zastąpiona, pełny identyfikator URI żądania jest przekazywany (ewentualnie modyfikowany).

Jeff
źródło