Tornado Remote IP

由于 Tornado 部署在 Nginx 后面,通过 self.request.remote_ip 总是只能拿到 Nginx 地址。

服务器上的 Nginx 配置如下:

upstream markjour {
    server 192.168.64.101:8081;
    server 192.168.64.101:8082;
    check  interval=5000 rise=1 fall=3 timeout=5000;
}

这样,同一台机器上的 Tornado 中拿到的都是 Nginx 访问 Tornado 时使用的地址:192.168.64.101。

看到很多人都在说需要在 Nginx 中设置 X-Forwarded-For,这是废话,当然设置了,比如我的服务器环境是这样的:

http {
    ...

    proxy_set_header    Host $http_host;
    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header    X-Real-IP $remote_addr;

    ...
}

通过 Bing 搜到 SO 上有一个回答,挺好的。

除了上面的步骤之外,还需要在启动服务时传入一个特殊参数:

server = httpserver.HTTPServer(application, xheaders=True)

或者直接读 HTTP Header:

self.request.headers.get('X-Real-Ip', '')

其他

顺便了解到一个小知识点:

  • 第一版配置:proxy_set_header X-Forwarded-For $remote_addr;
    如上配置只能增加负载均衡 IP 地址,丢失了客户端真实 IP 和任意中间代理 IP
  • 第二版配置:proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $remote_addr";
    如上配置在原有请求头 X-Forwarded-For 字段的基础上增加了连接 Nginx 的服务器 IP 地址
  • 第三版配置(最为简单):proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    $proxy_add_x_forwarded_for 已经实现了第二版的功能,直接使用该内置变量即可
    具体地址参见:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#var_proxy_add_x_forwarded_for
    如果要获取用户端的真实IP,应该从请求头中的 X-Forwarded-For 字段中取第一个英文逗号前的 IP 地址。