it-swarm.com.de

Stellen Sie sicher, dass nginx beim Reverseproxying den Hostnamen des Upstreams übergibt

Ich führe mehrere Docker-Container mit Hostnamen aus:

web1.local web2.local web3.local

Das Routing zu diesen erfolgt basierend auf dem Hostnamen von nginx. Ich habe einen Proxy vor diesem Setup (auf einem anderen Computer, der mit dem Internet verbunden ist), auf dem ich Upstream wie folgt definiere:

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

Und tatsächliche Beschreibung des virtuellen Hosts:

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

Da Container den Hostnamen "main" anstelle von "web1.local" erhalten, reagieren sie nicht richtig auf die Anforderung.

Frage: Wie kann ich nginx anweisen, den Namen des Upstream-Servers anstelle des Namens der Upstream-Gruppe von Servern im Host: -Header bei der Proxy-Anforderung zu übergeben?

94
pavel_karoukin

Eigentlich können Sie das über proxy_set_header tun.

Weitere Informationen finden Sie hier: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header oder sehen Sie sich hier einen Anwendungsbeispiel an: https: // stackoverflow .com/question/12847771/configure-nginx-with-proxy-pass

Ich habe den dynamischen Ansatz in Ihre oben veröffentlichte Konfiguration aufgenommen:

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

Hier ist ein Beispiel mit einem statischen Hostnamen:

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;
  }
}
115
Jens Bradler

Ich hatte das gleiche Problem und löste es schließlich mit zwei Proxy-Ebenen. Hier ist, wie Sie für Ihre Situation tun könnten (glaube ich):

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

Wie Sie sehen können, besteht der Trick darin, einen lokalen Server zu erstellen, der auf einen bestimmten Port reagiert und den Server als Proxy verwendet, indem der richtige Host für jeden Server neu geschrieben wird. Dann können Sie diese lokalen Server in Ihrem Upstream verwenden und diesen Upstream schließlich im realen Proxy verwenden.

28
ncenerar

Nachdem ich die gesamte Dokumentation für nginx gelesen hatte (ich konnte den Code für das Upstream-Modul nicht wirklich analysieren = =), kam ich auf diese bastardisierte Lösung. Leider verfolgt diese Lösung nicht die fehlgeschlagenen Hosts, sondern wählt einfach eine zufällige aus und leitet die Anforderung an diese weiter. Ich muss also eine Art Überwachung einrichten, um sicherzustellen, dass alle Backends ausgeführt werden.

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;
        }
}
3
pavel_karoukin

Wir übergeben die Upstream-Adresse als separaten Header wie diesen

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

Was ist, wenn Sie es versucht haben?

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;
  }
}
3
dalore

Während das Ziel logisch erscheint, nginx wird den Host: -Header nicht so ändern, dass er mit dem Upstream übereinstimmt . Stattdessen werden upstream -Domänennamen wie ein CNAME in DNS behandelt, um zu einer IP-Adresse zu gelangen.

Die Anforderungsheader (und der Hauptteil) werden festgelegt, bevor der Upstream ausgewählt wird. Der Upstream kann sich während der Anforderung ändern, wenn festgestellt wird, dass ein bestimmter Upstream nicht reagiert, die Anforderung sich jedoch nicht ändert.

2
GreenReaper

Hmm. Ich habe ein ähnliches Setup, in dem ich es einfach gemacht habe

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

Die Verwendung von $http_Host (der HTTP-Host-Header aus der eingehenden Anforderung) hier statt $Host (die Konfiguration des Server-Hostnamens) bewirkt, dass derselbe vom Client übergebene Host-Header in meinen Tests an den Upstream übergeben wird.

Siehe auch https://stackoverflow.com/questions/14352690/change-Host-header-in-nginx-reverse-proxy .

2
lyngvi

Wie andere Personen, die bereits mithilfe von Skriptvariablen (wie $ upstream) gepostet haben, können Sie diese nach Belieben festlegen. Dadurch wird das Problem ohne zusätzliches Header-Hacking behoben.

Bedrohungsskriptvariablen für den Proxy Pass-Handler auf andere Weise, wenn ein Wert nicht bedingt ist (der Name enthält kein $), werden in der Konfigurationsphase im Upstream gesichert und später verwendet.

Eine einfache Möglichkeit, dieses Problem zu beseitigen und die meisten Vorteile des Upstreams (kostenlose Version) zu nutzen, wäre die Verwendung von 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;
}

Das obige Beispiel sieht fast genauso aus wie Upstream. Es gibt andere Module, die das Mapping durchführen, d. H. chash_map_module , aber da sie nicht im Baum enthalten sind, müssen Sie sie selbst erstellen, was für einige Anwendungsfälle nicht möglich ist.

0
Mazeryt