web1.local
web2.local
web3.local
将它们路由到nginx基于主机名完成的路由。我在此设置(在连接到Internet的另一台计算机上)之前有一个代理,在其中我将上游定义为:
upstream main {
server web1.local:80;
server web2.local:80;
server web3.local:80;
}
以及实际的虚拟主机描述:
现在,由于容器收到的主机名是“ main”而不是“ web1.local”,因此它们无法正确响应请求。
问题:代理请求时,如何告诉nginx在Host:标头中传递上游服务器的名称而不是上游服务器组的名称?
#1 楼
实际上,您可以通过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;
}
}
评论
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for;似乎更好
– sivann
2014年5月24日9:00
@pavel:知道了。其实我也做了一些研究和测试。似乎没有直接的方法可以满足您的要求。因此,即使是“受重创”的解决方案也是解决方案。我不想问你为什么要这样做。我很确定你有你的理由。 :-)
–詹斯·布拉德勒
2014年5月25日晚上11:37
@JensBradler您似乎比我更专家,您能告诉我您对我的解决方案的看法吗?我想做同样的事情,因为我从ISP上的两个帐户运行了网站的两个副本:site1.myisp.com和site2.myisp.com,它们仅响应各自的名称。我现在拥有我的域名,我想使用我的ISP网站来平衡服务器的负载。那不是很好的理由吗?非常感谢你 ;)
–ncenerar
2014年8月20日15:45
@ncenerar您可以执行此操作,但这将导致单点故障:负载均衡器。如果这是用于负载平衡(不是冗余),则还可以将基于DNS的负载平衡与DNS故障转移结合使用。
–詹斯·布拉德勒
2014-09-24 18:28
该答案反映了官方博客的建议。
–伯纳德·罗塞(Bernard Rosset)
16年4月4日在16:05
#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
2014年8月20日在18:58
我不知道这会如何影响性能(添加额外的服务器{.. proxy_pass ...}层)
– KajMagnus
20年6月7日在20:33
#3 楼
尽管目标似乎合乎逻辑,但nginx不会更改Host:标头以匹配上游。而是像对待DNS中的upstream
一样对待CNAME
域名-作为一种获取IP地址的方法。在选择上游之前,请求标头(和正文)是固定的。如果发现特定上游没有响应,则上游可能会在请求中间进行更改,但请求不会更改。
#4 楼
因此,通过阅读有关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;
}
}
评论
如果使用此方法关闭上游主机会怎样?
–祖格里布
20年11月5日,0:46
#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;
}
}
如果尝试过该怎么办?
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;
}
}
#6 楼
嗯我有一个类似的设置,其中我只是在这里完成了location / {
...
proxy_set_header X-Forwarded-Host $http_host;
proxy_pass ...;
}
在这里使用
$http_host
(传入请求的HTTP主机头)而不是$host
(服务器主机名配置)在我的测试中导致客户端传递的同一Host标头传递到上游。另请参阅https://stackoverflow.com/questions/14352690/change-host -header-in-nginx-反向代理。
评论
根据docs nginx.org/en/docs/http/…,$host变量-其值等于“主机”请求标头字段中的服务器名称,或者等于该字段不存在时的主服务器名称-因此可能是$ host更好
– keypress
20-2-13在16:21
#7 楼
正如其他人已经使用脚本变量(例如$ upstream)发布的那样,您可以按自己喜欢的方式对其进行设置,这样就可以解决此问题,而无需进行其他标头黑客攻击。Proxy Pass处理程序中的威胁脚本变量另一种方法是,如果值不是有条件的(名称中没有$),则在配置阶段返回到上游并在以后使用。
一种简单的方法可以忽略此问题,并(免费版)上游的最大优势是使用类似
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,但是由于它们不在树中,因此您需要自己构建它们,这在某些用例/
中是不可能的
评论
我认为你不能。您为什么不将后端服务器设置为响应main或example.com?好像后端不知道是谁。反过来很容易实现:proxy_set_header主机$ host;将从上游返回的任何Host变量替换为原始请求的主机名。正确的做法是修复应用程序。
@MichaelHampton在某些情况下这是不可能的,例如,如果对TLS SNI使用proxy_ssl_server_name,则它需要正确的服务器名称。
恕我直言,这是Nginx中的错误。上游的名称“ main”只是.conf文件中的本地引用,不需要反映DNS可以解析的或后端已知的实际主机名。基本上,除非您的后端知道此引用或对主机做出响应:*您不能使用Nginx的上游指令。