Flask中request.remote_addr总为127.0.0.1是因Nginx反向代理导致,真实IP需通过可信代理透传的X-Forwarded-For头获取,且必须校验remote_addr是否在可信代理列表中才信任该头,推荐使用werkzeug.middleware.proxy_fix.ProxyFix中间件并显式配置trusted_proxies。

Flask里request.remote_addr为什么总是127.0.0.1
因为Nginx做了反向代理,Flask看到的TCP连接来源是Nginx本机,不是原始客户端。直接读request.remote_addr拿到的是Nginx的IP,不是用户真实IP。
必须依赖Nginx透传的HTTP头,最常用的是X-Forwarded-For。但不能无条件信任——这个头可被客户端伪造,必须只从可信代理(比如你自己的Nginx)后面才取它。
- Nginx配置里要加
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;,否则Flask根本收不到这个头 - Flask默认不解析
X-Forwarded-For,得自己写逻辑提取 - 如果Nginx和Flask之间还有其他代理(比如CDN、负载均衡),
X-Forwarded-For可能含多个IP,用逗号分隔,最左边才是用户真实IP(前提是链路可信)
怎么安全地从X-Forwarded-For取真实IP
不能直接request.headers.get("X-Forwarded-For", "").split(",")[0].strip()——这等于把伪造的头当真了。必须先确认请求确实来自可信代理。
推荐做法:把你的Nginx服务器IP(或网段)设为“可信代理列表”,只在request.remote_addr属于该列表时,才信任X-Forwarded-For。
立即学习“Python免费学习笔记(深入)”;
- 用Flask内置的
request.environ.get("HTTP_X_FORWARDED_FOR")比request.headers.get()更可靠(某些WSGI服务器会把头转成HTTP_*环境变量) - 真实IP取法:
ip_list = [ip.strip() for ip in (x_forwarded_for or "").split(",")],然后取ip_list[0],但仅当request.remote_addr在可信列表中 - 别忘了处理空值、格式错误(比如
" , 1.2.3.4, ")和IPv6压缩格式
Flask有没有现成方案?TrustProxyMiddleware靠谱吗
Flask本身不提供自动信任代理逻辑,但可以用werkzeug.middleware.proxy_fix.ProxyFix——它就是干这个的,但要注意版本和配置。
关键点:它不会“自动猜”哪些IP可信,必须显式指定trusted_hosts或trusted_proxies(v2.2+改名了)。
- v2.2+用法:
app.wsgi_app = ProxyFix(app.wsgi_app, trusted_proxies=["127.0.0.1", "10.0.0.0/8"]) - 旧版(trusted_hosts参数,但只支持域名/主机名,不支持IP段,慎用
- 启用后,
request.remote_addr会自动变成X-Forwarded-For里的第一个IP——但前提是请求真从你列的那些IP来,否则会被忽略 - 别在开发环境开这个,本地调试时
remote_addr是127.0.0.1,一开就全变错
为什么有时候拿到的是::1或者空字符串
::1是IPv6下的localhost,说明Nginx没正确传X-Forwarded-For,或者Flask收到的remote_addr是::1,但ProxyFix没把它列进trusted_proxies(IPv6地址要写成::1,不是127.0.0.1)。
空字符串常见于:Nginx配置漏了proxy_set_header、用了fastcgi协议但没配对应头、或者WSGI服务器(如Gunicorn)禁用了环境变量透传。
- 检查Nginx access log,确认
$http_x_forwarded_for字段有值 - 在Flask里打印
request.environ,搜HTTP_X_FORWARDED_FOR是否存在 - 如果用Gunicorn,确保没加
--no-env,且没在gunicorn.conf.py里清空env字段










