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.