使用 Nginx/Varnish/Apache 记录客户端 IP

使用 Nginx/Varnish/Apache 记录客户端 IP

我让 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;
    }
}

相关内容