Vraag Nginx omleiden via proxy, herschrijven en behouden van URL


In Nginx hebben we geprobeerd een URL als volgt om te leiden:

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

waar de gebruiker nog steeds de originele URL in zijn browser ziet. Nadat de gebruiker is omgeleid, zegt u dat deze op de koppeling naar klikt /section/index.html, we zouden willen dat dit een verzoek doet dat naar de omleiding leidt

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

en bewaar nogmaals de oorspronkelijke URL.

Bij onze pogingen zijn verschillende oplossingen betrokken met behulp van proxy's en herschrijfregels. Hieronder ziet u de configuratie die ons het dichtst bij een oplossing heeft gebracht (merk op dat dit de webserverconfiguratie is voor de example.com web Server). Er zijn echter nog steeds twee problemen met dit:

  • Het voert de herschrijving niet correct uit, in die zin dat de aanvraag-URL wordt ontvangen door de webserver http://192.168.1.24 omvat /some/path en slaagt daarom niet om de vereiste pagina te dienen.
  • Wanneer u de muisaanwijzer op een link houdt nadat een pagina is weergegeven, /some/path ontbreekt in de 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;
        }
    }
    

We zijn op zoek naar een oplossing waarbij alleen de configuratie van de webserver moet worden gewijzigd example.com. We kunnen de configuratie wijzigen 192.168.1.24 (ook Nginx), maar we willen dit proberen te vermijden, omdat we deze setup moeten herhalen voor honderden verschillende servers wiens toegang wordt benaderd via example.com.


63
2018-04-04 00:49


oorsprong




antwoorden:


Eerst moet u niet gebruiken root richtlijn binnen het locatieblok, het is een slechte gewoonte. In dit geval maakt het echter niet uit.

Probeer een tweede locatieblok toe te voegen:

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

Hiermee wordt het gedeelte na / some / pad / en vóór index.html vastgelegd in een variabele $ section, die vervolgens wordt gebruikt om de proxy_pass-bestemming in te stellen. U kunt de regex specifieker maken als u dat wilt.


54
2018-04-04 05:24



Excuses voor het late antwoord - dit is zo dicht bij het bereiken van wat we zoeken. De enige tekortkoming is dat, zodra de doelpagina is weergegeven, de URL's voor links in de browser '/ some / path /' niet bevatten, wat betekent dat ze niet werken als een gebruiker erop klikt. Als we kunnen uitzoeken hoe we dit kunnen oplossen, zal ik dit antwoord updaten en accepteren, omdat het er zo ongeveer is. - robjohncox
De koppelingen die de browser te zien krijgt, worden gegenereerd door de software die wordt uitgevoerd op de 192.168.1.24-server. U moet die software aanpassen om te bereiken wat u wilt. - Tero Kilkanen
niet zeker of ik je waarschuwing over root binnen locatieblok volg. het lezen van nginx-documentatie is de juiste manier om dingen te doen. ze waarschuwen slechte praktijken alleen omdat ze geen standaard root hebben buiten alle locaties. nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/... - guy mograbi
Welnu, het is gemakkelijker om een ​​vuistregel te gebruiken root in een location blokkeren, krijgt u geen onverwacht gedrag voor standaardlocaties. Alleen als u de standaardinstelling moet wijzigen root voor elke locatie, dan kunt u deze gebruiken. - Tero Kilkanen
Wat bedoel je met ontvangt de $ host als naam? Wat is de exacte HTTP-header die is verzonden en wat u precies wilt verzenden? - Tero Kilkanen


U moet URI-onderdeel gebruiken proxy_pass richtlijn. Ook heb je orderargumenten van gemengd proxy_redirect richtlijn, en waarschijnlijk heb je het helemaal niet nodig. Nginx heeft een redelijke standaard voor deze richtlijn.

In dit geval uw location blokkeren kan heel eenvoudig zijn:

location /some/path/ {
    proxy_pass http://192.168.1.24/;
    # note this slash  -----------^
    proxy_set_header Host $host;
}

55
2018-04-04 06:17



Excuses voor het late antwoord - ik heb dit geprobeerd en helaas werkt het niet voor onze use-case. Het probleem is dat, wanneer het verzoek wordt gedaan op de doelserver, de /some/path/ een deel van de URL wordt bewaard in het verzoek dat geen geldige URL is (we moeten ook de URL herschrijven om dit te verwijderen). - robjohncox
@robjohncox, wat heb je precies geprobeerd? - Alexey Ten
de schuine streep heeft de truc voor mij gedaan. Nu is mydomain.com/some/path/* correct proxy naar 192.168.1.24/* en niet 192.168.1.24/some/path/* - Vadimo
Kan ik de opmerking "# noteer deze schuine streep" in dit antwoord bijwerken? Drie gejuich voor die opmerking! - 8one6
Ik weet niet zeker hoe dit voor jullie werkt. Dit is wat ik probeer te bereiken. Wanneer een gebruiker echter op een link klikt die b.v. naar 192.168.1.24/login op de lokale service, wordt hij omgeleid naar mijndomein.com/login in plaats van mijndomein.com/some/path/login - mueslo


U kunt de volgende configuratie gebruiken om een ​​100% naadloze toewijzing tussen te maken /some/path/ aan de voorkant en / op de backend.

Merk op dat dit tot nu toe het enige antwoord is dat ook naadloos zou zorgen voor het genereren van absolute paden 404 Not Found fouten, op voorwaarde dat de juiste HTTP Referer header wordt verzonden door de browser, dus al die gifs moeten blijven laden zonder dat de onderliggende HTML hoeft te worden gewijzigd (wat niet alleen duur is, maar ook niet wordt ondersteund zonder extra modules die standaard niet zijn gecompileerd).

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";
}

Je kunt vinden het complete proof-of-concept en minimaal haalbare product binnen de https://github.com/cnst/StackOverflow.cnst.nginx.conf repository.

Hier is een testrun om te bevestigen dat alle randgevallen lijken te werken:

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

Postscriptum Als je veel verschillende paden hebt om in kaart te brengen, dan in plaats van een regex-vergelijking van $http_referer binnen een if binnen location @404, wilt u wellicht het op global gebaseerde gebruiken map richtlijn in plaats daarvan.

Merk ook op dat de achterliggende slashes in beide proxy_pass, net als de location het zit vervat in, zijn vrij belangrijk volgens een gerelateerd antwoord.

Referenties:


2
2017-08-27 03:42





Wanneer die schuine streep wordt toegevoegd aan een nginx proxied jenkins, wordt de foutmelding "Het lijkt erop dat uw reverse proxy is ingesteld gebroken" weergegeven.

proxy_pass          http://localhost:8080/;

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

Het zou moeten lezen

proxy_pass          http://localhost:8080;

1
2018-05-04 15:44