Fare in modo che nginx passi il nome host dell'upstream quando si esegue la reverseprox


89

Corro diversi container docker con nomi host:

web1.local web2.local web3.local

Il routing a questi è fatto in base al nome host di nginx. Ho un proxy di fronte a questa configurazione (su un'altra macchina connessa a Internet) dove definisco a monte come:

    upstream main {
      server web1.local:80;
      server web2.local:80;
      server web3.local:80;
    }

E descrizione dell'host virtuale effettivo:

    server {
      listen 80;
      server_name example.com;
      location / {
        proxy_pass http://main;
      }
    }

Ora, poiché i contenitori ricevono il nome host "main" anziché "web1.local", non rispondono correttamente alla richiesta.

Domanda: come posso dire a nginx di passare il nome del server upstream invece del nome del gruppo upstream di server in Host: header durante la richiesta proxy?


3
Non penso che tu possa. Perché non imposti i tuoi server back-end in modo che rispondano a main o example.com? Non è come se il backend non sa chi si è. Il contrario è prontamente possibile: proxy_set_header Host $ host; sostituirà qualsiasi variabile Host che ritorna dall'upstream con il nome host della richiesta originale.
Andrew Domaszek,

La cosa giusta da fare è riparare l'applicazione.
Michael Hampton

Risposte:


109

In realtà puoi farlo tramite proxy_set_header.

Per maggiori dettagli guarda qui: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header o vedi un caso d'uso qui: https://stackoverflow.com/questions/12847771/configure-nginx- con pass-proxy

Ho incluso l'approccio dinamico nella configurazione sopra pubblicata:

server {
  listen 80;
  server_name example.com;
  location / {
    proxy_pass       http://main;
    proxy_set_header Host            $host;
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

Ecco un esempio con un nome host statico:

server {
  listen 80;
  server_name example.com;
  location / {
    proxy_pass       http://main;
    proxy_set_header Host            www.example.com;
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

7
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for; sembra meglio
sivann

1
@pavel: capito. In realtà ho fatto anche alcune ricerche e alcuni test. Sembra che non esista un approccio diretto per soddisfare le tue esigenze. Quindi anche una soluzione "bastardata" è una soluzione. Non mi piace chiedere perché ti piacerebbe farlo. Sono abbastanza sicuro che tu abbia le tue ragioni. :-)
Jens Bradler,

@JensBradler Sembri più esperto di me, potresti dirmi cosa pensi della mia soluzione? Voglio fare lo stesso perché eseguo due copie del mio sito Web da due account sul mio ISP: site1.myisp.come site2.myisp.comrispondono solo al loro rispettivo nome. Ora possiedo il mio nome di dominio e vorrei utilizzare il mio sito Web ISP per bilanciare il carico dei miei server. Non è una buona ragione? Grazie mille;)
ncenerar

1
@ncenerar Puoi farlo ma questo ti porterà ad un singolo punto di errore: il bilanciamento del carico. Se questo è per il bilanciamento del carico (non ridondanza) è anche possibile utilizzare il bilanciamento del carico basato su DNS in combinazione con il failover DNS.
Jens Bradler,

2
Questa risposta riflette i consigli del blog ufficiale .
Bernard Rosset,

28

Ho avuto lo stesso problema e alla fine l'ho risolto utilizzando due livelli di proxy. Ecco come potresti fare per la tua situazione (penso):

server {
  listen      8001 default_server;
  server_name web1.example.com;
  location / {
    proxy_pass       http://web1.local:80;
    proxy_set_header Host web1.local:80;
  }
}

server {
  listen      8002 default_server;
  server_name web2.example.com;
  location / {
    proxy_pass       http://web2.local:80;
    proxy_set_header Host web2.local:80;
  }
}

server {
  listen      8003 default_server;
  server_name web3.example.com;
  location / {
    proxy_pass       http://web3.local:80;
    proxy_set_header Host web3.local:80;
  }
}

upstream main {
  server 127.0.0.1:8001;
  server 127.0.0.1:8002;
  server 127.0.0.1:8003;
}

server {
  listen      80;
  server_name example.com;
  location / {
    proxy_pass http://main;
  }
}

Come puoi vedere, il trucco è creare un server locale che risponda a una determinata porta che proxy il server riscrivendo l'host giusto per ciascun server. Quindi, è possibile utilizzare questi server locali nel proprio upstream e infine usarlo nel proxy reale.


Inizialmente ho usato l'approccio Lua, ma ora sono passato completamente a HAProxy che mi permette di fare esattamente quello che volevo con la configurazione standard.
pavel_karoukin,

3

Quindi, leggendo tutta la documentazione per nginx (non ho potuto davvero analizzare il codice per il modulo upstream = () ho trovato questa soluzione bastardata. Sfortunatamente questa soluzione non tiene traccia degli host falliti, ma seleziona semplicemente uno casuale e reindirizza la richiesta. Quindi devo impostare una sorta di monitoraggio per assicurarmi che tutti i backend siano in esecuzione.

server {
        listen 80;
        server_name example.com;
        resolver 127.0.0.1;

        location / {
                set $upstream "";
                rewrite_by_lua '
                        local upstreams = {
                                "http://web1.dokku.localdomain",
                                "http://web2.dokku.localdomain",
                                "http://web3.dokku.localdomain",
                                "http://web4.dokku.localdomain"
                        }
                        ngx.var.upstream = upstreams[ math.random( #upstreams ) ] 
                ';
                proxy_pass $upstream;
        }
}

2

Passiamo all'addstream a monte come un'intestazione separata come questa

server {
  listen 80;
  server_name example.com;
  location / {
    proxy_pass       http://main;
    proxy_set_header Host            $host;
    proxy_set_header X-Forwarded-For $remote_addr;
    add_header       X-Upstream      $upstream_addr;
  }
}

E se ci provassi?

server {
  listen 80;
  server_name example.com;
  location / {
    proxy_pass       http://main;
    proxy_set_header Host            $upstream_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    add_header       X-Host          $host;
  }
}


0

Hmm. Ho una configurazione simile, in cui ho semplicemente fatto

location / {
    ... 
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_pass ...;
}

L'uso di $http_host(l'intestazione Host HTTP dalla richiesta in arrivo) qui anziché $host(la configurazione del nome host del server) fa sì che la stessa intestazione Host passata dal client venga passata all'upstream, nel mio test.

Vedi anche https://stackoverflow.com/questions/14352690/change-host-header-in-nginx-reverse-proxy .


0

Dato che altre persone hanno già pubblicato usando la variabile di script (come $ upstream), puoi impostarlo come preferisci, e questo risolverà il problema, senza ulteriori hacking dell'intestazione.

Le variabili di script di minaccia del gestore Pass proxy in modo diverso, se un valore non è condizionale (non ha $ nel nome) viene eseguito il backup nell'upstream in fase di configurazione e l'utilizzo in un secondo momento.

Un modo semplice per omettere questo problema e avere i maggiori vantaggi di (versione gratuita) a monte sarebbe usare qualcosa del tipo Split_Clients:

split_clients $request_uri $my_upstream {
              33%          server1.domainX.com;
              33%          server2.domainX.com;
# Always use DOT at end entry if you wonder why, read the SC code.
              *            server3.domainX.com;  
}
location / {
    ... 
    proxy_pass http://$my_upstream;
}

L'esempio sopra sembra quasi uguale a monte. Esistono altri moduli che eseguono la mappatura, ovvero chash_map_module , ma poiché sono fuori dall'albero dovrai costruirli da soli, il che non è possibile per alcuni casi d'uso /

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.