Django 默认无法获取真实客户端IP,必须同时配置Nginx透传X-Forwarded-For头和Django的USE_X_FORWARDED_FOR=True及信任代理设置,否则REMOTE_ADDR始终为Nginx内网地址。

直接说结论:Django 默认拿不到真实客户端 IP,必须同时配置 Nginx 的 X-Forwarded-For 透传和 Django 的信任代理设置,否则 request.META.get('REMOTE_ADDR') 永远是 Nginx 的内网地址。
为什么 request.META['REMOTE_ADDR'] 总是 127.0.0.1 或内网地址?
Nginx 作为反向代理时,Django 接收到的 TCP 连接来源是 Nginx 本机,所以 REMOTE_ADDR 是 Nginx 的出口 IP(比如 127.0.0.1 或 10.0.2.2),不是用户真实 IP。Django 不会自动解析 X-Forwarded-For 头——它默认不信任任何代理传来的头信息,防止伪造。
常见错误现象:
- 日志里所有请求 IP 都是同一个(Nginx 地址)
-
get_client_ip()工具函数返回127.0.0.1,即使加了X-Forwarded-For头也无效 - 基于 IP 的限流、封禁、地理定位全部失效
Nginx 必须显式设置 X-Forwarded-For 和 X-Real-IP
只靠 Django 端改配置没用,Nginx 必须把原始 IP 以标准头形式透传过去。注意:proxy_set_header 必须写在 location 块里,且不能遗漏 $remote_addr。
立即学习“Python免费学习笔记(深入)”;
正确配置示例(在 location / 内):
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host;
关键点:
-
$proxy_add_x_forwarded_for会在原有X-Forwarded-For值后追加$remote_addr,避免多层代理时丢失最外层 IP - 不要写成
proxy_set_header X-Forwarded-For $remote_addr—— 这会覆盖掉上游可能已有的值,导致链路中段代理信息丢失 - 如果 Nginx 前面还有 CDN 或负载均衡(如 AWS ALB),需确认它是否已设
X-Forwarded-For;若已设,Nginx 应保留而非覆盖
Django 必须设置 SECURE_PROXY_SSL_HEADER 和 USE_X_FORWARDED_*
Django 从 1.9 开始废弃了 USE_X_FORWARDED_HOST 等独立开关,统一由 SECURE_PROXY_SSL_HEADER 和中间件行为控制。真实 IP 解析依赖两个设置:
-
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')—— 仅当需要识别 HTTPS 协议时才设(否则登录跳转可能变 HTTP) -
USE_X_FORWARDED_FOR = True—— 这个必须显式设为True(Django 默认是False),否则request.META.get('HTTP_X_FORWARDED_FOR')被忽略 -
SECURE_PROXY_SSL_HEADER不影响 IP 获取,只影响request.is_secure()和重定向协议
获取真实 IP 的推荐写法(兼容单层/多层代理):
def get_client_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0].strip()
else:
ip = request.META.get('REMOTE_ADDR')
return ip
注意:HTTP_X_FORWARDED_FOR 是 Django 自动将 X-Forwarded-For 头转成大写下划线格式后的键名,不是原始 header 名。
容易被忽略的坑:代理链长度与信任范围
如果你的流量路径是「用户 → CDN → Nginx → Django」,而只信任 Nginx(127.0.0.1),那么 CDN 添加的 X-Forwarded-For 会被 Django 当作不可信输入丢弃——因为 Django 默认只信任最后一跳代理的头。
解决方案只有两个:
- 让 CDN 直连 Django(绕过 Nginx),或
- 在 Nginx 中把 CDN 的真实 IP 段加入
set_real_ip_from,并启用real_ip_header X-Forwarded-For(需编译 Nginx 时带--with-http_realip_module)
没有中间代理时,USE_X_FORWARDED_FOR = True + 正确 Nginx 头就足够;一旦涉及多层,就必须明确每层代理的 IP 是否可信,否则 X-Forwarded-For 可被客户端伪造,带来安全风险。


















