Nginx Redirect über Proxy, Rewrite und Preserve URL

71

In Nginx haben wir versucht, eine URL wie folgt umzuleiten:

http://example.com/some/path -> http://192.168.1.24

wo der Benutzer noch die ursprüngliche URL in ihrem Browser sieht. Sobald der Benutzer umgeleitet wurde, sagen /section/index.htmlwir , dass er auf den Link zu klickt , möchten wir, dass dies eine Anfrage macht, die zur Umleitung führt

http://example.com/some/path/section/index.html -> http://192.168.1.24/section/index.html

und noch einmal die ursprüngliche URL beibehalten.

Unsere Versuche umfassten verschiedene Lösungen unter Verwendung von Proxys und Umschreibregeln. Im Folgenden wird die Konfiguration gezeigt, die uns einer Lösung am nächsten gebracht hat (beachten Sie, dass dies die Webserverkonfiguration für den example.comWebserver ist). Es gibt jedoch immer noch zwei Probleme:

  • Das erneute Schreiben wird nicht ordnungsgemäß ausgeführt, da die vom Webserver empfangene Anforderungs-URL die erforderliche Seite http://192.168.1.24enthält /some/pathund daher nicht bereitstellt.
  • Wenn Sie auf einem Link schweben, nachdem eine Seite geliefert wurde, /some/pathfehlt in der URL

    server {
        listen          80;
        server_name     www.example.com;
    
        location /some/path/ {
            proxy_pass http://192.168.1.24;
            proxy_redirect http://www.example.com/some/path http://192.168.1.24;
            proxy_set_header Host $host;
        }
    
        location / {
            index index.html;
            root  /var/www/example.com/htdocs;
        }
    }
    

Wir suchen nach einer Lösung, bei der nur die Webserverkonfiguration geändert werden muss example.com. Wir können die Konfiguration auf 192.168.1.24(auch auf Nginx) ändern , möchten dies jedoch vermeiden, da wir dieses Setup für Hunderte verschiedener Server wiederholen müssen, über die der Zugriff erfolgt example.com.

robjohncox
quelle

Antworten:

59

Erstens sollten Sie keine rootDirektive innerhalb des Location-Blocks verwenden, es ist eine schlechte Praxis. In diesem Fall spielt es jedoch keine Rolle.

Versuchen Sie, einen zweiten Standortblock hinzuzufügen:

location ~ /some/path/(?<section>.+)/index.html {
    proxy_pass http://192.168.1.24/$section/index.html;
    proxy_set_header Host $host;
}

Dadurch wird der Teil nach / some / path / und vor index.html in einer $ section-Variablen erfasst, die dann zum Festlegen des proxy_pass-Ziels verwendet wird. Sie können den regulären Ausdruck bei Bedarf präzisieren.

Tero Kilkanen
quelle
1
Entschuldigung für die verspätete Antwort - das ist so nah dran an dem, was wir suchen. Das einzige Manko ist, dass die URLs für Links im Browser nach dem Anzeigen der Zielseite nicht "/ some / path /" enthalten, was bedeutet, dass sie nicht funktionieren, wenn ein Benutzer darauf klickt. Wenn wir herausfinden können, wie wir das überwinden können, werde ich diese Antwort aktualisieren und akzeptieren, da sie so nah ist.
Robjohncox
8
Die vom Browser angezeigten Links werden von der Software generiert, die auf dem 192.168.1.24-Server ausgeführt wird. Sie sollten diese Software modifizieren, um das zu erreichen, was Sie wollen.
Tero Kilkanen
Ich bin mir nicht sicher, ob ich Ihrer Warnung zu root im Adressblock folge. Das Lesen der Nginx-Dokumentation ist der richtige Weg, um Dinge zu tun. Sie warnen nur vor schlechten Praktiken, wenn außerhalb aller Standorte keine Standardwurzel vorhanden ist. nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/…
guy mograbi
Nun, es ist einfacher, eine Faustregel zu haben, die nicht in rooteinem locationBlock verwendet wird, dann werden Sie kein unerwartetes Verhalten für Standardspeicherorte erhalten. Nur wenn Sie den Standard rootfür jeden Standort ändern müssen, können Sie ihn verwenden.
Tero Kilkanen
1
Was meinst du damit, den $ host als Namen zu erhalten ? Was ist der genaue HTTP-Header, der gesendet wurde und was genau soll er senden?
Tero Kilkanen
65

Sie sollten den URI-Teil in der proxy_passDirektive verwenden. Außerdem haben Sie die Ordnungsargumente der proxy_redirectDirektive vertauscht, und wahrscheinlich brauchen Sie sie überhaupt nicht. Nginx hat einen angemessenen Standard für diese Richtlinie.

In diesem Fall könnte Ihr locationBlock sehr einfach sein:

location /some/path/ {
    proxy_pass http://192.168.1.24/;
    # note this slash  -----------^
    proxy_set_header Host $host;
}
Alexey Ten
quelle
1
Entschuldigung für die verspätete Antwort - ich habe es ausprobiert und leider funktioniert es nicht für unseren Anwendungsfall. Das Problem ist, dass bei der Anforderung auf dem Zielserver der /some/path/Teil der URL in der Anforderung erhalten bleibt, der keine gültige URL ist (wir müssen auch die URL neu schreiben, um diese zu entfernen).
Robjohncox
@robjohncox was genau hast du probiert?
Alexey Ten
9
Der Schrägstrich hat den Trick für mich getan. Jetzt wird mydomain.com/some/path/* korrekt an 192.168.1.24/* und nicht an 192.168.1.24/some/path/* weitergeleitet
Vadimo 18.11.14
7
Kann ich den Kommentar "# note this slash" in dieser Antwort verbessern? Ein Hoch auf diesen Kommentar!
8one6
Ich bin mir nicht sicher, wie das für euch alle funktioniert. Das versuche ich zu erreichen. Wenn ein Benutzer jedoch auf einen Link klickt, der zum Beispiel zu 192.168.1.24/login im lokalen Dienst umleitet, wird er zu mydomain.com/login anstelle von mydomain.com/some/path/login
mueslo
4

Sie können die folgende Konfiguration verwenden, um eine 100% nahtlose Zuordnung zwischen /some/path/dem Front-End und /dem Back -End zu erzielen.

Beachten Sie, dass dies die einzige Antwort ist, die sich auch nahtlos um die Erzeugung von 404 Not FoundFehlern bei absoluten Pfaden kümmert , vorausgesetzt, Refererder Browser sendet den richtigen HTTP- Header. Daher sollten alle diese Gifs weiterhin geladen werden, ohne dass der zugrunde liegende HTML-Code geändert werden muss (Das ist nicht nur teuer, sondern wird auch ohne zusätzliche Module, die nicht standardmäßig kompiliert wurden, nicht unterstützt.)

location /some/path/ {
    proxy_pass http://192.168.1.24/; # note the trailing slash!
}
location / {
    error_page 404 = @404;
    return 404; # this would normally be `try_files` first
}
location @404 {
    add_header Vary Referer; # sadly, no effect on 404
    if ($http_referer ~ ://[^/]*(/some/path|/the/other)/) {
        return 302 $1$uri;
    }
    return 404 "Not Found\n";
}

Sie finden den vollständigen Proof-of-Concept und das Produkt mit minimaler Lebensfähigkeit im Repository https://github.com/cnst/StackOverflow.cnst.nginx.conf .

Hier ist ein Testlauf, um zu bestätigen, dass alle Edge-Fälle zu funktionieren scheinen:

curl -v -H 'Referer: http://example.su/some/path/page.html' localhost:6586/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location
> GET /and/more.gif HTTP/1.1
> Referer: http://example.su/some/path/page.html
< HTTP/1.1 302 Moved Temporarily
< Location: http://localhost:6586/some/path/and/more.gif
< Vary: Referer

curl -v localhost:6586/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location
> GET /and/more.gif HTTP/1.1
< HTTP/1.1 404 Not Found

curl -v localhost:6586/some/path/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location -e uri
> GET /some/path/and/more.gif HTTP/1.1
< HTTP/1.1 200 OK
request_uri:    /and/more.gif

PS : Wenn Sie viele verschiedene Wege haben, kartieren dann anstelle eines regex Vergleich zu tun , $http_refererinnerhalb eines ifinnerhalb location @404, könnte man die globale Basis verwenden möchten mapRichtlinie statt.

Beachten Sie auch, dass die abschließenden Schrägstriche sowohl in dem proxy_passals auch in dem , in dem locationes enthalten ist, gemäß einer verwandten Antwort ziemlich wichtig sind .

Verweise:

cnst
quelle
2

Wenn dieser Schrägstrich zu einem Nginx-Proxy-Jenkin hinzugefügt wird, wird der Fehler "Offenbar ist Ihr Reverse-Proxy-Setup fehlerhaft" angezeigt.

proxy_pass          http://localhost:8080/;

Remove this -----------------------------^

Es sollte lesen

proxy_pass          http://localhost:8080;
Tomdunn
quelle
Ich glaube nicht, dass dies das ist, worauf sich die Frage des OP bezog, und auch nicht, um eines der genannten Probleme zu lösen.
Cory Robinson