Nginx Reverse Proxy + Umschreiben der URL

149

Nginx läuft auf Port 80, und ich bin mit ihm Proxy - URLs mit Pfad umkehren /foozu Port auf 3200diese Weise:

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

Dies funktioniert einwandfrei, aber ich habe eine Anwendung auf dem Port 3200, für die ich nicht möchte, dass die Initiale /fooan gesendet wird. Das heißt - wenn ich darauf zugreife http://localhost/foo/bar, möchte ich nur /barder Pfad sein, wie er von der App empfangen wird. Also habe ich versucht, diese Zeile zum obigen Standortblock hinzuzufügen:

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

Dies bewirkt eine Weiterleitung 302 (Änderung der URL), aber ich möchte 301. Was soll ich tun?

Jeffreyveon
quelle
Wenn Sie Probleme mit dem Grafana-Fall haben, sollten Sie das folgende Rezept verwenden: docs.grafana.org/installation/behind_proxy/…
mohsen saeedi

Antworten:

168

Jegliche Weiterleitung zu localhost ist auf einem entfernten System (z. B. dem Webbrowser des Clients) nicht sinnvoll. Daher sind die Umschreibungsflags permanent (301) oder umleiten (302) in Ihrem Fall nicht verwendbar.

Bitte versuchen Sie das folgende Setup mit einer transparenten Umschreiberegel:

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

Verwenden curl -iSie diese Option, um Ihre Umschreibungen zu testen. Eine sehr subtile Änderung der Regel kann dazu führen, dass Nginx eine Umleitung durchführt.

Jens Bradler
quelle
1
Der URL-Pfad beginnt immer noch mit / foo in meiner App, wenn ich das tue ...
Jeffreyveon
Es muss ein anderes Problem geben. Ich habe dieses Szenario vor wenigen Minuten erfolgreich reproduziert. Ursprüngliche URL: http: // development / foo / testme / 1234 - REQUEST_URI eines PHP-Skripts, das auf einem als Proxy verbundenen Apache ausgeführt wird: '/ testme / 1234'
Jens Bradler
9
Die Regex sollte wahrscheinlich sein /foo(.*), sonst wird example.com/foonicht abgestimmt. (das ist wahrscheinlich, was Jeffreyveon erlebt hat)
Benno
Diese Art von Arbeiten, aber mein Körper, den ich mit proxy_set_body einstelle, wird entfernt.
Justin Thomas
rewrite /(.*) /socket.io/ break; Sparen
Sie
123

Der einfache Abgleich von Standortpräfixen funktioniert ohne Verwendung einer Umschreiberegel, solange Sie einen URI in der Anweisung proxy_pass angeben:

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

Beachten Sie den Zusatz /am Ende der proxy_passRichtlinie. NGINX entfernt das übereinstimmende Präfix /foound übergibt den Rest an den Back-End-Server am URI /. Daher http://myserver:80/foo/barwird im Backend unter gepostet http://localhost:3200/bar.

In den NGINX-Dokumenten zu proxy_pass :

Wenn die Anweisung proxy_pass mit einem URI angegeben wird, wird bei der Übergabe einer Anforderung an den Server der Teil einer normalisierten Anforderungs-URI, der mit dem Speicherort übereinstimmt, durch einen in der Anweisung angegebenen URI ersetzt:

DanArl
quelle
12
Funktioniert für mich, als ich / zu location / foo / {
Andrei N
Genau das habe ich gesucht!
8.
6
Dies ist eine sehr saubere Lösung, ich würde es vorziehen, wenn dies die kanonische Antwort auf die Frage ist.
Italien
2
Es dauerte zu lange, um die Wichtigkeit des Beibehaltens oder Entfernens des nachgestellten Schrägstrichs zu erkennen.
Parvez
5
Dies wird tatsächlich //xyzan den Host übergeben, wenn Sie das tun.
Archimedes Trajano
60

Der absolut korrekteste Weg und die beste Vorgehensweise lauten normalerweise wie folgt:

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

  • Beachten Sie, wie wichtig der abschließende Schrägstrich istproxy_pass , der die $uriVariable automatisch so ändert , dass sie /foo/im Frontend mit /der im Backend übereinstimmt . Keine explizite rewriteAnweisung erforderlich .

  • Beachten Sie außerdem, dass das Nachziehen /derlocation URL ebenfalls sehr wichtig ist. Ohne diese Angabe besteht die Gefahr, dass Ihre Website an einem bestimmten Punkt komisch aussehende URLs enthält (z. B. eine /fooenzusätzliche URL /foo/en).

    Darüber hinaus stellt das Nachziehen /des locationwith proxy_passauch eine spezielle Behandlung gemäß der Dokumentation der locationDirektive sicher , um auch ein Implizit effektiv zu verursachen location = /foo {return 301 /foo/;}.

    Wenn Sie also ein locationmit dem abschließenden Schrägstrich wie oben definieren, stellen Sie nicht nur sicher, dass URLs ohne Suffix wie /fooenungültig sind, sondern auch, dass ein /fooohne abschließenden Schrägstrich weiterhin funktioniert.


Referenzdokumentation:

cnst
quelle
Es sieht aus wie $argsverloren: http://frontend/foo?bar=bazwird zu proxied http://backend/. Beachten Sie, dass Argumente nicht Teil der URL sind
Vanuan
@ Vanuan, bist du dir da sicher? Ich bin mir ziemlich sicher, $argsdass Sie trotzdem angemessen damit umgehen sollten, wenn Sie den obigen Code verwenden, da sie von diesem getrennt $urisind und wieder zusammengesetzt werden sollten, es sei denn, Sie verwenden explizite Variablen in Ihrem Code proxy_pass.
3.
@cnst Oh, ich verstehe. Ich benutze die Host-Variable. Das ist kontraintuitiv.
Vanuan
1
@ArchimedesTrajano, Sie sind falsch, da es eine spezielle Behandlung gibt, /foozu der umgeleitet werden muss. Wenn Sie also /foo/im Backend nichts Seltsames tun, /foofunktionieren auch Anfragen mit dem obigen Code. (Dies ist eigentlich schon Teil der Antwort, Übrigens.)
7.
3
Während diese Lösung in all diesen Foren "zu gewinnen" scheint, sollte in der Antwort selbst angemerkt werden, dass Nginx die URL entschlüsselt und die entschlüsselte URL an den Proxy-Server weiterleitet. Diese Lösung funktioniert also nicht, wenn Ihre URL URL-codierte Teile enthält.
Codierung
1

Versuchen

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

oder

location ^~ /foo {
    proxy_pass http://localhost:3200/;
    ....
DerGeh
quelle
13
Diese Antwort wäre gut, wenn Sie erklären würden, warum sie wie oben konfiguriert werden muss.
Masegaloeh
Dies wird tatsächlich //xyzan den Host übergeben, wenn Sie das tun.
Archimedes Trajano
1

@Terabuck Es tut uns leid, dass wir noch nicht geantwortet haben.

Sie sollten localhost nicht verwenden, da Sie davon abhängig sind, dass die Anwendung auf einem Server mit einer Hosts-Datei ausgeführt wird. Lokaler Host ist nur eine Standardübersetzung auf 127.0.0.1. Es gibt nichts, was besagt, dass Sie diese Hosts-Dateien haben müssen. Es ist nur sehr verbreitet, einen zu haben.

Eine Loopback-Schnittstelle zu haben, ist wieder eine weitere häufige Sache, von der Sie abhängig sind, aber Sie sind immer noch von der Loopback-Schnittstelle auf dem Netzwerkstapel abhängig. Es ist ein seltener Fall, diese beiden nicht zu haben. Wenn Sie sich jemals darum sorgen. Zumindest unter Unix / Linux haben Sie die Möglichkeit für Sockets. Dadurch muss der Netzwerkstapel nicht mehr den lokalen Host erreichen. Gehen Sie bei diesem Ansatz mit Vorsicht vor, da einige Faktoren auf dem Host-Betriebssystem eine Rolle spielen. Wie die Anzahl der geöffneten Dateien usw.

Cody Van Lith
quelle