清漆缓存ip地址请求

时间:2021-06-07 08:11:22

标签: header haproxy varnish

我的设置是 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)

我该怎么办?

提前致谢

2 个答案:

答案 0 :(得分:0)

在 Varnish 中识别原始客户端 IP 地址的最佳方法是通过常规的 X-Forwarded-For 标头,该标头由 Varnish 自动设置。

X-Forwarded-For 的问题

人们经常遇到的问题是,他们在 Varnish 前面有另一台服务器(在您的情况下为 HaProxy),因此 X-Forwarded-For 值始终相同。

用于救援的代理协议

Varnish 支持 PROXY protocol。该协议扩展了 TCP/IP 数据包并存储来自原始客户端 IP 的连接信息,而不管流量必须经过多少跳。

<块引用>

如果 Varnish 配置了 PROXY 协议支持,它会自动将 X-Forwarded-For 值设置为原始客户端 IP。

在 Varnish 中启用代理协议支持

如果您配置了正确的监听接口,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 中启用代理协议

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

这样一切正常。

非常感谢!