必须借助 ngx_http_geoip2_module 模块配合 maxmind geolite2 数据库实现;需正确配置数据库路径、log_format 变量引用、realip 模块还原真实 ip,并注意隐私合规与数据库定期更新。

要在 Nginx 的 access_log 中记录客户端 IP 的区域信息(如国家、省份、城市),不能仅靠内置变量实现,必须借助第三方模块或外部服务。Nginx 本身不解析 IP 地理位置,需通过 ngx_http_geoip2_module(推荐)或旧版 geoip 模块配合 MaxMind GeoLite2 数据库完成。
使用 GeoIP2 模块获取并记录区域信息
这是当前最主流、准确且持续更新的方案。它支持 IPv4/IPv6,数据源为 MaxMind GeoLite2 免费数据库(需注册下载)。
- 确认已编译安装
ngx_http_geoip2_module(OpenResty 或自编译 Nginx 均可支持;Windows 下需手动编译或选用含该模块的预编译包) - 下载 GeoLite2 City 数据库(
GeoLite2-City.mmdb),存放到安全路径(如conf/geoip2/) - 在
http块中加载数据库并定义变量:
geoip2 conf/geoip2/GeoLite2-City.mmdb {
$geoip2_data_country_code country iso_code;
$geoip2_data_country_name country names en;
$geoip2_data_province_name subdivisions 0 names en;
$geoip2_data_city_name city names en;
}
- 在
log_format中引用这些变量,例如:
log_format geo '[$time_local] $remote_addr "$request" $status $body_bytes_sent "$geoip2_data_country_name" "$geoip2_data_province_name" "$geoip2_data_city_name" "$http_user_agent"';
access_log logs/access_geo.log geo;
使用tbot机器ID身份文件配合tsh CLI,通过Teleport访问控制SSH登录托管主机或执行远程命令。
确保真实客户端 IP 被用于地理查询
若 Nginx 前有 CDN 或负载均衡器,$remote_addr 是代理 IP,直接查会得到代理所在地。必须先启用 realip 模块还原真实 IP,再让 GeoIP2 基于该 IP 查询:
- 配置
set_real_ip_from指定可信代理网段(如 CDN 的 IP 段) - 设置
real_ip_header X-Forwarded-For并开启real_ip_recursive on - GeoIP2 模块默认作用于
$remote_addr,而realip模块会将其替换为真实 IP —— 二者天然协同,无需额外指定变量
替代方案:通过 Lua + HTTP API 异步补全(适合小流量或调试)
若无法部署 GeoIP2 模块(如受限于 Windows 环境或权限),可用 OpenResty 的 Lua 脚本调用免费 IP 归属地 API(如 ip-api.com),但要注意:
- 免费接口有请求频率限制(通常 45 次/分钟),不适合高并发生产环境
- 需用
log_by_lua_block在日志写入前注入字段,避免阻塞主请求流 - 返回结果需缓存(如用 lrucache)降低延迟和失败率
- 日志格式中需预留占位符,Lua 中动态填充,例如:
'$remote_addr $geo_country $geo_city ...'
验证与注意事项
配置完成后务必验证:
- 检查 Nginx 启动是否报错(如模块未找到、mmdb 文件路径错误、权限不足)
- 用
curl -H "X-Forwarded-For: 8.8.8.8" http://your-site/测试,查看日志中是否出现 “United States” “California” “Mountain View” - 注意隐私合规:部分地区要求对 IP 地理信息做匿名化或用户授权,避免直接记录精确到街道的位置
- GeoLite2 数据库需定期更新(MaxMind 提供每月更新链接),建议用脚本自动下载替换










