用 nginx+Gunicorn 部署 Flask 应用,调整了 nginx 的配置很多次,重新编译安装 nginx ,也添加了 ngx_http_realip_module ,但是在 Flask 应用里获取到用户 ip 始终是 127.0.0.1.
* 如果前端去掉 nginx+Gunicorn, 直接跑 Flask 自带的 wsgi ,是可以成功获取用户的访问 ip 。
nginx 配置如下:
nginx version: nginx/1.8.0
built by gcc 4.8.2 (Ubuntu 4.8.2-19ubuntu1)
configure arguments: --prefix=/usr/local/nginx --with-pcre=/usr/src/pcre-8.36 --with-http_realip_module
server {
listen 80;
server_name mydomain.com;
location / {
proxy_pass http://127.0.0.1:8000;
# set_real_ip_from 127.0.0.1;
# real_ip_header X-Forwarded-For;
# real_ip_recursive on;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
1
humiaozuzu 2015-11-15 22:07:03 +08:00 2
werkzeug 获取 ip 的默认是你 nginx 的 ip 了,也就是说不是真实的 ip ,下面的代码可以解决问题
from werkzeug.contrib.fixers import ProxyFix app.wsgi_app = ProxyFix(app.wsgi_app) |
2
lins05 2015-11-15 22:43:39 +08:00
改成 `proxy_set_header X-Forwarded-For $remote_addr` 试试
|
3
zhuangzhuang1988 2015-11-15 22:53:04 +08:00
先直接 在 flask 中 把传入的 env 都打印出来先..
|
4
rogwan OP @lins05 最开始就是这样配置的,无效;改为 X-Real-IP $remote_addr 也不行。
@humiaozuzu 还是取的本地 ip... 先让 Gunicorn 裸跑着吧,这样直接获取用户的 ip 是 OK 的(把前端的 nginx 去掉了),还不清楚 nginx 和 gunicorn 的配合哪儿出问题了 |
5
julyclyde 2015-11-16 12:30:41 +08:00
nginx 配置如下只是 nginx 负责任的传递了这个信息在 header 里
至于是否读那个 header ,那是 python 这边的事 |
6
xiangace 2015-11-16 13:34:54 +08:00
headers.environ.get("HTTP_X_Forwarded_For", headers.get('HTTP_X_REAL_IP', request.remote_addr))
|
7
rogwan OP @xiangace 兄弟,你试过这样能生效吗?怎么我用你说的方法,不行啊...
我原来的写法是: from flask import request def get_real_ip(): ip = request.remote_addr 这样直接用 Flask 自带的 wsgi 跑,或用 Gunicorn 跑 mydomain.com:80 端口,都是可以成功获取用户真实 ip 的,但 Gunicorn 前面再套一层 nginx 就不行的。 |
10
rogwan OP @julyclyde 看了一下 Gunicorn 的核心开发者 Starefossen 今年 5 月做了这样一个说明:
#633 removed functionality which made Gunicron update REMOTE_ADDR to what a trusted upstream client sent in the X-Forwared-For header. This was a violation of RFC 3875 CGI Version 1.1 which states the following: 4.1.8. REMOTE_ADDR The REMOTE_ADDR variable MUST be set to the network address of the client sending the request to the server. Because of this change, if your Gunicorn server is behind any proxy you will only get the proxy's IP address as the REMOTE_ADDR. I think there should be some sort of mention of this pitfall in the documentation along with a suggested good workaround (if there exists any). I'll see if I get the time to submit a PR at the end of this weekend. =========== 应用程序是不能通过 Gunicorn (版本阶段应该是 Guniconr19.0+吧)来取 REMOTE_ADDR 了(这个值是空的),而 X-forwarded_for 的 client ip 值容易被修改和伪造(实际测试中发现,通过微信内置浏览器访问的话,这个值会取不到)。 |