Come riscrivo gli URL in una risposta proxy in NGINX


87

Sono abituato a usare Apache con mod_proxy_html e sto cercando di ottenere qualcosa di simile con NGINX. Il caso d'uso specifico è che ho un'interfaccia utente di amministrazione in esecuzione in Tomcat sulla porta 8080 su un server nel contesto root:

http://localhost:8080/

Ho bisogno di farlo apparire sulla porta 80, ma ho altri contesti sul server NGINX in esecuzione su questo host, quindi voglio provare ad accedervi su:

http://localhost:80/admin/

Speravo che il seguente blocco server super semplice lo avrebbe fatto, ma non è così:

server {
    listen  80;
    server_name screenly.local.akana.com;

    location /admin/ {
        proxy_pass http://localhost:8080/;
    }
}

Il problema è che il contenuto restituito (html) contiene URL di script e informazioni di stile a cui si accede nel contesto radice, quindi è necessario che questi URL vengano riscritti per iniziare con / admin / invece di /.

Come posso farlo in NGINX?

Risposte:


128

Dovremmo prima leggere attentamente e completamente la documentazione su proxy_pass .

L'URI passato al server upstream è determinato in base al fatto che la direttiva "proxy_pass" venga utilizzata con URI o meno. La barra finale nella direttiva proxy_pass significa che l'URI è presente ed è uguale a /. L'assenza di una barra finale significa che l'URI del cappello è assente.

Proxy_pass con URI :

location /some_dir/ {
    proxy_pass http://some_server/;
}

Con quanto sopra, c'è il seguente proxy:

http:// your_server/some_dir/ some_subdir/some_file ->
http:// some_server/          some_subdir/some_file

Fondamentalmente, /some_dir/viene sostituito da /per modificare il percorso della richiesta da /some_dir/some_subdir/some_filea /some_subdir/some_file.

Proxy_pass senza URI :

location /some_dir/ {
    proxy_pass http://some_server;
}

Con la seconda (nessuna barra finale): il proxy funziona così:

http:// your_server /some_dir/some_subdir/some_file ->
http:// some_server /some_dir/some_subdir/some_file

Fondamentalmente, il percorso completo della richiesta originale viene passato senza modifiche.


Quindi, nel tuo caso, sembra che dovresti semplicemente rilasciare la barra finale per ottenere ciò che desideri.


Avvertimento

Nota che la riscrittura automatica funziona solo se non usi le variabili in proxy_pass. Se usi le variabili, dovresti riscriverti:

location /some_dir/ {
  rewrite    /some_dir/(.*) /$1 break;
  proxy_pass $upstream_server;
}

Ci sono altri casi in cui la riscrittura non funzionerebbe, ecco perché leggere la documentazione è d'obbligo.


modificare

Leggendo di nuovo la tua domanda, sembra che mi sia perso il fatto che vuoi solo modificare l'output html.

Per questo, puoi usare la direttiva sub_filter . Qualcosa di simile a ...

location /admin/ {
    proxy_pass http://localhost:8080/;
    sub_filter "http://your_server/" "http://your_server/admin/";
    sub_filter_once off;
}

Fondamentalmente, la stringa che si desidera sostituire e la stringa di sostituzione


2
Grazie, questo aiuta molto. Penso che sub_filter lo farà.
IanG

2
Sono curioso di sapere fino a che punto nginx sta già riscrivendo l'output, non dovrebbe almeno riscrivere l'host / hostname nei collegamenti? Quindi, ad esempio, non vorrestisub_filter "http://localhost/" "http://localhost/admin/"
ThorSummoner

1
Per consentire una riscrittura diversa dal text/htmlmimetype, ho dovuto aggiungere anche sub_filter_types *;.
anttikoo

Qualcosa di strano sta accadendo per me con questa soluzione. Risorse (* .js, * .css ecc. Vengono recuperate), ma la pagina non viene caricata. mi aspetterei http://your_server/admin/di essere risolto http://your_serverdurante il proxy_pass ma non lo fa e ricevo un errore react-router /admin/ location did not match any routesnella mia applicazione perché la mia applicazione non sa nulla di '/ admin'.
Prachi

Potrebbe anche essere necessario aggiungere la proxy_redirectdirettiva in modo che anche l' Locationintestazione inviata dalla risposta venga modificata in base all'URL. Dai
vivanov

22

Potrebbe anche essere necessario impostare la seguente direttiva prima del primo "sub_filter" per i server di backend con compressione dei dati:

proxy_set_header Accept-Encoding "";

Altrimenti potrebbe non funzionare. Per il tuo esempio sembrerà:

location /admin/ {
    proxy_pass http://localhost:8080/;
    proxy_set_header Accept-Encoding "";
    sub_filter "http://your_server/" "http://your_server/admin/";
    sub_filter_once off;
}

-1

È possibile utilizzare il seguente esempio di configurazione di nginx:

upstream adminhost {
  server adminhostname:8080;
}

server {
  listen 80;

  location ~ ^/admin/(.*)$ {
    proxy_pass http://adminhost/$1$is_args$args;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $server_name;
  }
}

1
Perché questo è downvoted? Qualche problema con il codice? Mi sembra una soluzione carina e complessa, che risolve alcuni avvertimenti relativi al proxy di un'app che viene visualizzata in seguito. Non sono sicuro del perché proxy_redirect off;però. Inoltre aggiungerei proxy_set_header X-Forwarded-Proto $scheme;.
LuH
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.