负载平衡器 – >清漆 – > Nginx

我现在头痛了几个小时,想看看有没有人可以帮忙。

1)我有一台负载均衡器,后端有6台服务器。

2)后台服务器是Nginx,为了获得访问者的真实IP地址,我只需要在每个Nginx安装中进行以下操作,我就可以得到每个访客的真实客户端IP地址。

set_real_ip_from 192.168.255.0/24; <-- to handle the load balancer IP real_ip_header X-Forwarded-For; 

3)现在,我已经在每个在127.0.0.1上执行caching的Nginx前安装了Varnish,由于某种原因,现在Nginx并没有看到来自LoadBalancer的实际客户端IP地址 – > Varnish – > Nginx

这是打印以下内容:

IP地址:192.168.255.9 < – 这应该是真正的客户端IP地址,而不是192.168(假设正在打印负载均衡器IP地址)

更详细的主机地址:192.168.255.9

很多谢谢,如果你能帮助。

戴夫

更新:

没有清漆的方程中,我有以下LB – > NGINX和NGINX内存在

 set_real_ip_from 192.168.255.0/24; real_ip_header X-Forwarded-For; 

当NGINXloggingremote_addr时,下面的第一个条目打印真实的客户端IP地址

 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; 213.205.234.x - - [05/Sep/2012:09:42:08 -0700] "GET /2011/10/28/chicken-and-apples-in- honey-mustard-sauce/ HTTP/1.1" 200 18283 "-" "Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; GT-I9100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30" "213.205.234.x" 

用方程式LB – > Varnish – > NGINX

在NGINX中,我将set_real_ip_from切换到127.0.0.1

 set_real_ip_from 127.0.0.1; real_ip_header X-Forwarded-For; 

NGINX中的$ remote_addr不打印真实的客户端IP地址:

 192.168.255.9 - - [05/Sep/2012:09:46:41 -0700] "GET /2012/09/03/stuffed-baked-potatoes-deconstructed/ HTTP/1.1" 200 18159 "-" "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; ADR6400L Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1" "69.255.125.x, 192.168.255.9" 

从上面你可以看到,正在打印的$ remote_addr是负载均衡器的IP地址:192.168.255.9,而不是客户端的remote_addr。 虽然“$ http_x_forwarded_for”打印正确的地址我猜:“69.255.125.x,192.168.255.9”。 我的目标是让$ remote_addr保持正确的IP地址

谢谢戴夫

更新:

这是我的Varnish的default.vcl,注释了Shane提到的部分,这里是来自NGINX访问日志的当前输出

 127.0.0.1 - - [05/Sep/2012:11:16:43 -0700] "GET /wp-content/plugins/wp-pagenavi/pagenavi-css.css?ver=2.70 HTTP/1.1" 304 0 "http://mobilefoodblog.com/2011/10/28/chicken-and-apples-in-honey-mustard-sauce/" "Mozilla/5.0 (Linux; U; Android 2.3.5; en-us; SCH-I405 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1" "67.168.209.192, 192.168.255.9" # This is a basic VCL configuration file for varnish. See the vcl(7) # man page for details on VCL syntax and semantics. # # Default backend definition. Set this to point to your content # server. # backend default { .host = "localhost"; .port = "8080"; } sub detect_device { # Define the desktop device set req.http.X-Device = "desktop"; if (req.http.User-Agent ~ "iP(hone|od)" || req.http.User-Agent ~ "Android" || req.http.User-Agent ~ "iPad") { # Define smartphones and tablets set req.http.X-Device = "smart"; } elseif (req.http.User-Agent ~ "SymbianOS" || req.http.User-Agent ~ "^BlackBerry" || req.http.User-Agent ~ "^SonyEricsson" || req.http.User-Agent ~ "^Nokia" || req.http.User-Agent ~ "^SAMSUNG" || req.http.User-Agent ~ "^LG") { # Define every other mobile device set req.http.X-Device = "other"; } } acl purge { "localhost"; } sub vcl_recv { call detect_device; # if (req.restarts == 0) { # if (req.http.x-forwarded-for) { # set req.http.X-Forwarded-For = # req.http.X-Forwarded-For ", " client.ip; # } else { # set req.http.X-Forwarded-For = client.ip; # } # } if (req.request == "PURGE") { if (!client.ip ~ purge) { error 405 "Not allowed."; } return(lookup); } if (req.url ~ "^/$") { unset req.http.cookie; } } sub vcl_hit { if (req.request == "PURGE") { set obj.ttl = 0s; error 200 "Purged."; } } sub vcl_miss { if (req.request == "PURGE") { error 404 "Not in cache."; } if (!(req.url ~ "wp-(login|admin)")) { unset req.http.cookie; } if (req.url ~ "^/[^?]+.(jpeg|jpg|png|gif|ico|js|css|txt|gz|zip|lzma|bz2|tgz|tbz|html|htm)(\?.|)$") { unset req.http.cookie; set req.url = regsub(req.url, "\?.$", ""); } if (req.url ~ "^/$") { unset req.http.cookie; } } sub vcl_fetch { if (req.url ~ "^/$") { unset beresp.http.set-cookie; } if (!(req.url ~ "wp-(login|admin)")) { unset beresp.http.set-cookie; } } sub vcl_hash { set req.hash += req.url; if (req.http.host) { set req.hash += req.http.host; } else { set req.hash += server.ip; } # And then add the device to the hash (if its a mobile device) if (req.http.X-Device ~ "smart" || req.http.X-Device ~ "other") { set req.hash += req.http.X-Device; } return (hash); } 

由于Varnish运行在每个运行nginx的服务器上,从nginx的angular度来看,连接的来源是127.0.0.1,而不是负载平衡器。

 set_real_ip_from 192.168.255.0/24; 

那就是问题所在; 当连接源自127.0.0.1(varnish进程)时,nginx不会“信任” X-Forwarded-For头文件; 信任的只是整个192.168.255.0/24networking。 当Varnish发送它时添加一个授权来信任标题。

 set_real_ip_from 127.0.0.1; 

编辑:

nginx在parsing“真实”客户端IP的X-Forwarded-For头时performance不好; 它会查找标题中的最后一个条目,如果有多个条目,则永远不会是真正的客户端IP。 看到这个问题的更多信息在这个问题上。

我build议让Varnish停止添加自己的X-Forwarded-For标题。 你会想要vcl_recv这部分的vcl_recv函数:

 if (req.restarts == 0) { if (req.http.x-forwarded-for) { set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; } else { set req.http.X-Forwarded-For = client.ip; } } 

提供您当前的vclconfiguration,如果您需要帮助,需要为您更改,因为这可能是明确configuration或附加的默认值(或两者)。

编辑2:

交换这个在varnishconfiguration中的vcl_recv函数; 它会将您configuration的定制与默认行为相结合,同时删除默认情况下存在的X-Forwarded-For技巧。

 sub vcl_recv { call detect_device; if (req.request == "PURGE") { if (!client.ip ~ purge) { error 405 "Not allowed."; } return(lookup); } if (req.url ~ "^/$") { unset req.http.cookie; } # Default logic follows; it's normally appended. # It'll still be appended, but having the return(lookup) # prevents its use. X-Forward-For header behavior removed. if (req.request != "GET" && req.request != "HEAD" && req.request != "PUT" && req.request != "POST" && req.request != "TRACE" && req.request != "OPTIONS" && req.request != "DELETE") { /* Non-RFC2616 or CONNECT which is weird. */ return (pipe); } if (req.request != "GET" && req.request != "HEAD") { /* We only deal with GET and HEAD by default */ return (pass); } if (req.http.Authorization || req.http.Cookie) { /* Not cacheable by default */ return (pass); } return (lookup); } 

这听起来像你的负载平衡器没有通过任何头的客户端IP地址。 由于您没有说明负载平衡器使用的是什么,因此不可能提供特定的解决scheme,但通常情况下,您希望将负载平衡器configuration为将客户端IP地址放在其中一个标头中(例如X-Forwarded-For )。 如果你愿意,你也可以指定一个自定义标题。

如果您的负载平衡器设置了X-Forwarded-For,那么我会configuration您的Varnish服务器来设置X-Forwarded-For以外的标头,以便您可以全面了解客户端的IP地址和哪个服务器处理请求。

假设您的负载均衡器使用HTTP和HTTPS的X-Forwarded-For标头,那么…

…在清漆你应该有这个

 sub vcl_recv { ... set req.http.X-Forwarded-For = req.http.X-Forwarded-For; 

在Nginx中你应该有这个

 server { ... set_real_ip_from 192.168.255.0/24; real_ip_header X-Forwarded-For; 

我将补充一点,你应该只运行1个Varnish实例,它违背了拥有多个caching的目的(因为负载平衡器可能会将请求传递给未启动的Varnish实例)。 你的命中率会更糟,更不要说它只是浪费资源。