我让 Nginx 监听端口 443 作为 SSL 终止器,并将未加密的流量代理到同一台服务器上的 Varnish。Varnish 3 正在处理此流量以及直接通过端口 80 传入的流量。所有流量均以未加密的形式传递到集群中其他服务器上的 Apache 实例。Apache 实例使用 mod_rpaf 将记录的客户端 IP 替换为 X-Forwarded-For 标头的内容。
我的问题是,如果流量来自 Nginx,而“正确的”客户端 IP 记录在 VarnishNCSA 日志中,则看起来 Varnish 正在(可以理解)用下游的 127.0.0.1 替换 Nginx 的 X-Forwarded-For 标头,并且这会被记录到 Apache 中。如果 X-Forwarded-For 已经填充,有没有一种简单易行的方法可以阻止 Varnish 重写它?
答案1
当然;Varnish 的处理X-Forwarded-For
实际上只是在默认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;
}
}
函数的默认定义始终附加到您在活动 VCL 文件中定义的函数,但如果您定义的函数始终处理请求,则默认逻辑将永远不会执行。
设置vcl_recv
如下:
sub vcl_recv {
/* Your existing logic goes here */
/* After that, we'll insert the default logic, with the X-Forwarded-For handling removed */
/* The return (lookup); at the end ensures that the default append behavior won't have an impact */
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);
}
编辑:
由于 Varnish 也直接处理某些连接,因此更好的方法可能是让它有选择地设置标头。您仍然需要包含完整内容vcl_recv
,以便默认不会应用其自己的标头,但在顶部包含以下内容:
if (req.restarts == 0) {
if (!req.http.x-forwarded-for) {
set req.http.X-Forwarded-For = client.ip;
}
}