Reindirizzamento Nginx tramite proxy, riscrivi e conserva URL


71

In Nginx abbiamo cercato di reindirizzare un URL come segue:

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

dove l'utente vede ancora l'URL originale nel proprio browser. Una volta che l'utente viene reindirizzato, supponiamo che /section/index.htmlfaccia clic sul collegamento a , vorremmo che questo facesse una richiesta che porta al reindirizzamento

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

e ancora preservare l'URL originale.

I nostri tentativi hanno coinvolto varie soluzioni che utilizzano proxy e riscrivono le regole e di seguito mostra la configurazione che ci ha avvicinato di più a una soluzione (si noti che questa è la configurazione del server Web per il example.comserver Web). Tuttavia, ci sono ancora due problemi con questo:

  • Non esegue correttamente la riscrittura, in quanto http://192.168.1.24include l'URL della richiesta ricevuto dal server Web /some/pathe quindi non riesce a servire la pagina richiesta.
  • Quando passi con il mouse su un link una volta che una pagina è stata pubblicata, /some/pathmanca dall'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;
        }
    }
    

Stiamo cercando una soluzione che implichi solo la modifica della configurazione del server Web example.com. Siamo in grado di cambiare la configurazione 192.168.1.24(anche Nginx), tuttavia vogliamo provare a evitarlo perché dovremo ripetere questa configurazione per centinaia di server diversi il cui accesso è proxy example.com.

Risposte:


59

Innanzitutto, non dovresti usare la rootdirettiva all'interno del blocco posizione, è una cattiva pratica. In questo caso non importa però.

Prova ad aggiungere un secondo blocco di posizione:

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

Questo acquisisce la parte after / some / path / e before index.html in una variabile $ section, che viene quindi utilizzata per impostare la destinazione proxy_pass. Puoi rendere il regex più specifico se lo desideri.


1
Ci scusiamo per la risposta tardiva: è così vicino al raggiungimento di ciò che stiamo cercando. L'unico difetto è che, una volta che la pagina di destinazione è stata pubblicata, gli URL per i collegamenti nel browser non includono '/ some / path /', il che significa che non funzionano se un utente fa clic su di essi. Se riusciamo a capire come superare questo, aggiornerò e accetterò questa risposta, dato che è quasi lì.
robjohncox,

8
I collegamenti visualizzati dal browser sono generati dal software in esecuzione sul server 192.168.1.24. È necessario modificare quel software per ottenere ciò che si desidera.
Tero Kilkanen,

non sono sicuro di seguire il tuo avviso su root all'interno del blocco di posizione. leggere la documentazione di nginx è il modo giusto di fare cose. avvertono solo le cattive pratiche di non avere una radice predefinita al di fuori di tutte le posizioni. nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/…
guy mograbi

Bene, è più facile avere una regola empirica da non usare rootall'interno di un locationblocco, quindi non otterrai alcun comportamento imprevisto per le posizioni predefinite. Solo se è necessario modificare il valore predefinito rootper ogni posizione, è possibile utilizzarlo.
Tero Kilkanen,

1
Cosa intendi con $ host come nome ? Qual è l'esatta intestazione HTTP che è stata inviata e che cosa esattamente vuoi che invii?
Tero Kilkanen,

65

È necessario utilizzare la parte URI nella proxy_passdirettiva. Inoltre, hai confuso gli argomenti di ordine della proxy_redirectdirettiva e probabilmente non ne hai affatto bisogno. Nginx ha un ragionevole default per questa direttiva.

In questo caso il tuo locationblocco potrebbe essere davvero semplice:

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

1
Ci scusiamo per la risposta tardiva - l'ho provato e sfortunatamente non funziona per il nostro caso d'uso. Il problema è che, quando la richiesta viene effettuata sul server di destinazione, la /some/path/parte dell'URL viene mantenuta nella richiesta che non è un URL valido (è necessario riscrivere anche l'URL per rimuoverlo).
robjohncox,

@robjohncox cosa hai provato esattamente?
Alexey Ten,

9
la barra ha fatto il trucco per me. Ora mydomain.com/some/path/* viene inviato correttamente a 192.168.1.24/* e non 192.168.1.24/some/path/*
Vadimo,

7
Posso aggiungere il commento "# note this slash" in questa risposta? Tre saluti per quel commento!
8one6,

Non sono sicuro di come funzioni per tutti voi. Questo è quello che sto cercando di ottenere. Tuttavia, quando un utente fa clic su un collegamento che reindirizzerebbe, ad esempio, a 192.168.1.24/login sul servizio locale, viene reindirizzato a mydomain.com/login invece di
mydomain.com/some/path/login

4

È possibile utilizzare la seguente configurazione per avere una mappatura perfetta al 100% tra /some/path/front-end e /back-end.

Si noti che questa è l'unica risposta finora che si occuperebbe anche di percorsi assoluti che generano 404 Not Founderrori, a condizione che Refereril browser invii l' intestazione HTTP corretta , quindi tutte quelle gif dovrebbero continuare a caricarsi senza che sia necessario modificare l'HTML sottostante (che non è solo costoso, ma non è supportato senza moduli aggiuntivi non compilati per impostazione predefinita).

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

Puoi trovare il completo proof-of-concept e il minimo-fattibile-prodotto nel repository https://github.com/cnst/StackOverflow.cnst.nginx.conf .

Ecco una serie di test per confermare che tutti i casi limite sembrano funzionare:

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 Se hai molti percorsi diversi da mappare, allora invece di fare un confronto regex $http_refererall'interno di un ifinterno location @404, potresti voler usare mapinvece la direttiva globale .

Si noti inoltre che le barre finali sia in proxy_pass, sia in locationcui sono contenute, sono piuttosto importanti secondo una risposta correlata .

Riferimenti:


2

Quando la barra viene aggiunta a un jenkins con proxy nginx, viene visualizzato l'errore "Sembra che la configurazione del proxy inverso sia rotta".

proxy_pass          http://localhost:8080/;

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

Dovrebbe leggere

proxy_pass          http://localhost:8080;

Non penso che questo sia ciò a cui la domanda del PO era collegata né risolve nessuno dei problemi menzionati.
Cory Robinson,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.