You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby on Rails在Heroku环境下获取的用户IP与设备实际IP不一致问题

Heroku环境下Rails获取真实用户IP的调整方案

根因定位

对照你贴的日志就能直接定位问题:

  • Heroku平台输出的访问日志里,fwd="136.xx.xx.xxx,172.xx.xx.xx" 已经存了完整的请求转发链,第一个值就是你家庭测试设备的真实公网IP,第二个是Heroku内部代理的内网地址
  • 应用日志里打印的Started GET "/" for 198.xx.xx.xx,拿到的是Heroku边缘路由节点的出口IP,和真实用户位置完全无关

出现这个偏差的核心原因是:Rails默认的可信代理白名单只覆盖常规私有网段,没有把Heroku的代理链路纳入信任范围,框架不会主动从X-Forwarded-For(也就是日志里的fwd字段)里提取真实用户IP,只会把最后一跳直连到dyno的代理IP当作请求来源。

配置调整步骤

1. 修正生产环境可信代理规则

打开 config/environments/production.rb,调整可信代理的配置项,叠加Heroku专用的内部代理网段:

# config/environments/production.rb
# 保留框架默认的可信私有网段,追加Heroku内部代理IP段
config.action_dispatch.trusted_proxies = [
  ActionDispatch::RemoteIp::TRUSTED_PROXIES,
  IPAddr.new("172.16.0.0/12")
]

172.16.0.0/12是Heroku所有内部代理节点使用的固定网段,刚好覆盖你日志里看到的172开头的内网转发地址。配置完成后,Rails会自动把这个网段的代理判定为可信,从转发的IP链路上剥离所有可信代理的地址,把最靠前的真实用户IP作为请求来源IP返回。

2. 适配现有取数逻辑

可信代理规则生效后,不需要额外手动拆分转发头取IP:

  • 直接用request.remote_ip就能拿到经过安全校验的真实用户IP
  • 原有的geocoder gem、ipinfo_io组件会自动读取这个修正后的IP值,不会再拿到之前198段的边缘节点IP
  • 不要手动直接读取request.headers['X-Forwarded-For']的第一个值,这种写法存在IP伪造的安全风险,必须依赖Rails自带的可信代理校验逻辑处理。

3. 效果验证

  • 修改配置后重启dyno,让新规则生效
  • 可以临时加个测试路由快速验证识别结果:
    # config/routes.rb
    get '/debug_ip', to: ->(env) { [200, {}, [env['action_dispatch.remote_ip'].to_s]] }
    
    访问该路由返回的IP如果和你本地查询的公网IP一致,就说明配置已经生效,验证完记得删掉这个临时路由。

避坑提示

  • 不要为了图省事把整个公网网段设为可信代理,会引入IP伪造的安全风险,只追加172.16.0.0/12网段就完全匹配Heroku的转发链路
  • 生产环境的配置有缓存,修改完如果不重启dyno,旧规则会一直生效
  • 不要硬编码取fwd字段的第一个值,Heroku的转发链路如果后续调整网段,硬编码逻辑会直接失效。

内容的提问来源于stack exchange,提问作者Splohr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.26 04:45:00