リバースプロキシするときにnginxがアップストリームのホスト名を渡すようにする


89

ホスト名を使用していくつかのdockerコンテナーを実行します。

web1.local web2.local web3.local

これらへのルーティングは、nginxによるホスト名に基づいて行われます。このセットアップの前に(インターネットに接続されている別のマシン上に)プロキシがあり、アップストリームを次のように定義しています。

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

実際の仮想ホストの説明:

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

現在、コンテナは「web1.local」ではなく「main」というホスト名を受け取るため、リクエストに適切に応答しません。

質問:要求をプロキシするときに、Host:ヘッダーでサーバーの上流グループの名前の代わりに上流サーバーの名前を渡すようにnginxに指示するにはどうすればよいですか?


3
できるとは思わない。mainまたはexample.comに応答するようにバックエンドサーバーを設定しないのはなぜですか?バックエンドがそれが誰あるかを知らないかのようではありません。その逆はすぐに可能です:proxy_set_header Host $ host; アップストリームから返されるホスト変数を元のリクエストのホスト名に置き換えます。
アンドリュードマゼク

適切なことは、アプリケーションを修正することです。
マイケルハンプトン

回答:


109

実際、proxy_set_headerを介してそれを行うことができます。

詳細については、http//nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_headerをご覧になるか、ユースケースの例をご覧くださいhttps : //stackoverflow.com/questions/12847771/configure-nginx- with-proxy-pass

上記の構成に動的アプローチを含めました。

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

静的ホスト名を使用した例を次に示します。

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; 良さそうです
sivann

1
@pavel:わかった。実際、私はいくつかの研究といくつかのテストも行いました。要件を満たすための直接的なアプローチはないようです。そのため、「やつれた」解決策でさえ解決策です。なぜあなたがこれをしたいのか尋ねたくありません。理由があると確信しています。:-)
イェンスブラッドラー

@JensBradlerあなたは私よりも専門家のようですので、私の解決策についてどう思われますか?私は私のISPに2つのアカウントから私のウェブサイトの2つのコピーを実行するので、私は同じことをやってみたい。site1.myisp.comそしてsite2.myisp.com、彼らはそれぞれの名前に対応しています。現在、ドメイン名を所有しているため、ISP Webサイトを使用してサーバーの負荷分散を行いたいと考えています。それは正当な理由ではありませんか?ありがとうございました;)
ncenerar 14

1
@ncenerarそれはできますが、これにより単一の障害点、ロードバランサーに到達します。これが(冗長性ではなく)ロードバランシング用である場合、DNSフェイルオーバーと組み合わせてDNSベースのロードバランシングを使用することもできます。
イェンスブラッドラー14


28

私は同じ問題を抱えていたので、2つのレベルのプロキシを使用して最終的に解決しました。あなたの状況にどのように対処できるかを次に示します(私は思う):

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

ご覧のとおり、トリックは特定のポートに応答するローカルサーバーを作成し、各サーバーの適切なホストを書き換えることにより、サーバーをプロキシします。次に、アップストリームでこのローカルサーバーを使用し、最終的に実際のプロキシでそのアップストリームを使用できます。


私はもともとLuaアプローチを使用していましたが、今では標準の構成で必要なことだけを行うことができるHAProxyに完全に切り替えました。
pavel_karoukin 14

3

したがって、nginxのすべてのドキュメントを読んで(上流モジュールのコードを実際に解析できませんでした=()この粗悪なソリューションを思い付きました。残念ながら、このソリューションは失敗したホストを追跡せず、単にランダムなものを選択してリクエストをリダイレクトしますそのため、すべてのバックエンドが実行されていることを確認するために、何らかの監視を設定する必要があります。

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

このような独立したヘッダーとしてアップストリームaddrを渡します

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

試したらどうしますか?

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

2

目標は論理的に思えますが、nginxはHost:ヘッダーをアップストリームに一致するように変更しません。代わりに、DNSのupstreamようにドメイン名を扱いますCNAME-IPアドレスを取得する方法として。

要求ヘッダー(および本文)は、アップストリームが選択される前に修正されます。特定のアップストリームが応答しないことが判明した場合、アップストリームはリクエストの途中で変更できますが、リクエストは変更されません。


0

うーん。同様の設定があり、単純に完了しました

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

使用$http_host(着信要求からのHTTPホストヘッダー)、ここではなく、$host(サーバのホスト名の設定)は、クライアントから渡された同じホストヘッダーが私のテストでは、上流に渡されるようにします。

https://stackoverflow.com/questions/14352690/change-host-header-in-nginx-reverse-proxyも参照してください


0

他の人が既にスクリプト変数($ upstreamなど)を使用して投稿しているので、好きなように設定できます。これにより、追加のヘッダーハッキングなしで問題が修正されます。

値が条件付きでない(名前に$がない)場合、プロキシパスハンドラーの脅威スクリプト変数は別の方法で構成フェーズでアップストリームにバックアップされ、後で使用されます。

この問題を省略し、(無料版)アップストリームの最大の利点を得る簡単な方法は、次のようなものを使用することです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;
}

上記の例は、アップストリームとほとんど同じように見えます。マッピングを行う他のモジュール、つまりchash_map_moduleが存在しますが、それらはツリーの外にあるので、自分でそれらを構築する必要があります。これは、いくつかのユースケース/

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.