我的设置是 HAPROXY -> Varnish -> Origin
带有 forwardfor 选项的 Haproxy,将客户端原始 IP 转发到 Varnish:
option forwardfor header X-HEADER-IP
我希望 Varnish 在响应中打印一个标头 Remote-IP,所以我定义了:
set beresp.http.Remote-IP = bereq.http.X-HEADER-IP;
函数内部vcl_backend_response
当我使用来自 Machine1 (IP1) 的 CURL 发出第一个请求时,我有一个具有正确远程 IP 地址的 MISS:
Machine1 (IP1)$ curl -I https://foo.bar
HTTP/2 200
server: nginx
content-type: text/html; charset=utf-8
**remote-ip: IP1**
via: 1.1 varnish (Varnish/6.6)
vary: Accept-Encoding, Cookie, User-Agent
x-varnish-beresp: 200
x-varnsih-cache: MISS
如果我从另一台机器(位于另一个网络 IP2)发出相同的请求,我会收到一个 HIT,但远程 IP 与第一个请求相同,因为(我认为)已从 Varnish 缓存。
Machine2 (IP2)$ curl -I https://foo.bar
HTTP/2 200
server: nginx
content-type: text/html; charset=utf-8
**remote-ip: IP1**
via: 1.1 varnish (Varnish/6.6)
vary: Accept-Encoding, Cookie, User-Agent
x-varnish-beresp: 200
x-varnsih-cache: HIT
我希望第二个请求给我一个 HIT,但我希望在 Remote-IP 标头中有正确的 IP 地址 (IP2)
我该怎么办?
提前致谢
答案 0 :(得分:0)
在 Varnish 中识别原始客户端 IP 地址的最佳方法是通过常规的 X-Forwarded-For
标头,该标头由 Varnish 自动设置。
人们经常遇到的问题是,他们在 Varnish 前面有另一台服务器(在您的情况下为 HaProxy),因此 X-Forwarded-For
值始终相同。
Varnish 支持 PROXY protocol。该协议扩展了 TCP/IP 数据包并存储来自原始客户端 IP 的连接信息,而不管流量必须经过多少跳。
<块引用>如果 Varnish 配置了 PROXY 协议支持,它会自动将 X-Forwarded-For
值设置为原始客户端 IP。
如果您配置了正确的监听接口,Varnish 可以监听传入的 PROXY 连接。
通常,您将拥有这样的 Varnish 配置:
varnishd -a :6081 -p feature=+http2 -f /etc/varnish/default.vcl -s malloc,256m
您可以通过添加以下监听接口来启用代理支持:
-a :8443,PROXY
完整的流程如下:
varnishd -a :6081 -a :8443,PROXY -p feature=+http2 -f /etc/varnish/default.vcl -s malloc,256m
有了额外的监听接口,现在只需要配置 HaProxy
HaProxy 的伟大之处在于他们发明了 PROXY 协议。启用它非常容易。
想象一下在 HaProxy 中有以下 Varnish 后端配置:
backend varnish
mode http
server varnish 127.0.0.1:6081 check
只需将 send-proxy-v2
添加到服务器定义中即可。
最终结果如下:
backend varnish
mode http
server varnish 127.0.0.1:6081 check send-proxy-v2
一旦 Varnish 和 HaProxy 通过 PROXY 协议进行通信,您就可以依靠 X-Forwarded-For
标头始终显示原始客户端 IP 地址。
所以这是配置它的最佳方式。还有一种快速而肮脏的方法。
假设 X-HEADER-IP
请求标头由 HaProxy 发送并包含原始客户端 IP,您还可以使用以下 VCL 代码段来计算每个请求的远程 IP:
sub vcl_deliver {
set resp.http.Remote-IP = req.http.X-HEADER-IP;
}
答案 1 :(得分:0)
感谢 Thijs Feryn 的回答,我已经解决了! 我遵循了使用 X-Forwarded-For 的建议,并且还在 HAProxy 和 Varnish 中启用了代理协议。因此,他们现在正在启用该功能。 但是,也使用 X-Forwarded-For 标头而不是自定义标头,我的问题与我所描述的相同。
相反,当我将代码移动到 vcl_deliver 函数时,我确实解决了这个问题,正如 Quick & Dirty 部分所建议的那样。
我的最终目标是拥有一个带有 IP 地址所在国家/地区代码的 cookie __cc。
import geoip2;
import header;
sub vcl_deliver {
...
set resp.http.Remote-IP = req.http.X-Forwarded-For; #Just for test
set req.http.X-Country-Code = country.lookup("country/iso_code", std.ip(req.http.X-Forwarded-For, "0.0.0.0"));
set req.http.Set-CookieCC = "__cc="+req.http.X-Country-Code+"; path=/; Max-Age=300; SameSite=none; Secure";
set resp.http.set-cookie = header.get(req.http.set-cookieCC,"__cc");
}
这样一切正常。
非常感谢!