反向代理时让 nginx 传递上游的主机名

pav*_*kin 122 nginx reverse-proxy

我用主机名运行了几个 docker 容器:

web1.local web2.local web3.local

由 nginx 根据主机名路由到这些。我在此设置(在连接到互联网的不同机器上)前面有一个代理,我将上游定义为:

    upstream main {
      server web1.local:80;
      server web2.local:80;
      server web3.local:80;
    }
Run Code Online (Sandbox Code Playgroud)

和实际的虚拟主机描述:

    server {
      listen 80;
      server_name example.com;
      location / {
        proxy_pass http://main;
      }
    }
Run Code Online (Sandbox Code Playgroud)

现在,因为容器接收主机名“main”而不是“web1.local”,它们不能正确响应请求。

问题:如何在代理请求时告诉 nginx 在 Host: 标头中传递上游服务器的名称而不是上游服务器组的名称?

Jen*_*ler 138

其实你可以通过proxy_set_header来做到这一点。

有关更多详细信息,请查看此处:http : //nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header或在此处查看示例用例:https : //stackoverflow.com/questions/12847771/configure-nginx-带代理通行证

我已将动态方法包含在您上面发布的配置中:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

这是一个带有静态主机名的示例:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 看起来更好 (8认同)
  • 这个答案意味着“$host”变量被设置为“upstream”块“server”指令中服务器名称的值,但这似乎与文档不匹配。如果 nginx 选择“web1.local:80”作为目标,则“$host”是否设置为“web1.local:80”或“example.com”(“server_name”中的第一个值)?后者可能有效,但这不是最初要求的。 (4认同)
  • @pavel:明白了。其实我也做了一些研究和一些测试。似乎没有直接的方法来满足您的要求。所以即使是“混蛋”的解决方案也是一个解决方案。我不想问你为什么要这样做。我很确定你有你的理由。:-) (2认同)
  • 这个答案反映了[官方博客的建议](https://www.nginx.com/resources/admin-guide/reverse-proxy/)。 (2认同)
  • 这个答案是不正确的 - 只有当你的 NGINX 在与你的后端响应相同的主机上被调用时,将传入的 `$host` 变量传递到你的后端才会起作用 - 这是不太可能的情况。 (2认同)

小智 33

我遇到了同样的问题,我最终通过使用两级代理解决了它。以下是您可以为您的情况做的事情(我认为):

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,诀窍是创建一个响应特定端口的本地服务器,该服务器将通过为每个服务器重写正确的主机来代理服务器。然后,您可以在上游使用此本地服务器,并最终在实际代理中使用该上游。


Gre*_*per 9

虽然目标似乎合乎逻辑,但nginx 不会更改 Host: 标头以匹配 upstream。相反,它将upstream域名视为CNAMEDNS 中的 a - 作为获取 IP 地址的一种方式。

在选择上游之前,请求标头(和正文)是固定的。如果发现上游没有响应,上游可能会在请求中更改,但请求不会更改。


小智 5

我们将上游地址作为单独的标头传递,如下所示

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

如果你尝试过怎么办?

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 不会。在评估“proxy_set_header”时,$upstream_addr 仍然为空,稍后会选择它。 (2认同)