nginx 可通过 geo 模块或 geoip2 模块在请求处理阶段实时解析访客地理位置并写入日志:geo 模块适用于静态 ip 段国家标记,性能高;geoip2 模块基于 maxmind geolite2 数据库,支持城市、经纬度等精准字段,需配置真实 ip 获取逻辑(set_real_ip_from + x-forwarded-for)以确保准确性。

直接在 Nginx 日志中记录访客地理位置,关键不是“事后解析”,而是利用 geo 模块或 geoip2 模块,在请求处理阶段就完成 IP 到地理信息(如国家、城市、经纬度)的映射,并将结果注入日志字段。这比依赖 Logstash 或 Kibana 后期解析更轻量、实时性更高。
用 geo 模块做粗粒度国家/区域标记
geo 模块适合做简单、静态的 IP 段归属映射,比如按国家代码打标、区分内网/海外流量、屏蔽特定区域等。它不依赖外部数据库,纯配置驱动,性能极高。
- 在
http块中定义映射规则,例如:
geo $remote_addr $geo_country {
default "ZZ";
192.168.0.0/16 "LAN";
203.123.45.0/24 "CN";
198.51.100.0/24 "US";
} - 注意:如果 Nginx 前有代理(如 CDN、负载均衡),需配合
set_real_ip_from+real_ip_header X-Forwarded-For,确保$remote_addr是真实客户端 IP,否则映射失效 - 在
log_format中引用该变量:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
"$status $body_bytes_sent" "$http_referer" "$http_user_agent" "$geo_country";
用 ngx_http_geoip2_module 做精准城市级定位
这是目前最主流、推荐的方式。它基于 MaxMind 的 GeoLite2 数据库(免费版足够生产使用),支持国家、省、市、经纬度、时区等完整字段,且支持动态更新。
- 安装模块(以 Ubuntu + nginx-extras 为例):
sudo apt install libnginx-mod-http-geoip2
sudo nginx -V 2>&1 | grep -o with-http-geoip2-module # 确认已编译 - 下载并配置 GeoLite2-City.mmdb(需注册 MaxMind 获取免费 License Key):
sudo mkdir -p /usr/share/GeoIP/
wget https://github.com/maxmind/geoipupdate/releases/download/v5.3.0/geoipupdate_5.3.0-1~focal1_amd64.deb
# 或手动下载 mmdb 并放至 /usr/share/GeoIP/GeoLite2-City.mmdb - 在
http块中加载数据库与变量:
geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
$geoip2_data_city_name source=$remote_addr city name;
$geoip2_data_latitude source=$remote_addr location latitude;
$geoip2_data_longitude source=$remote_addr location longitude;
} - 日志格式中直接使用这些变量:
log_format geo_json '{ "@timestamp": "$time_iso8601",'
"country": "$geoip2_data_country_code",'
"city": "$geoip2_data_city_name",'
"lat": "$geoip2_data_latitude",'
"lon": "$geoip2_data_longitude" }';
注意真实 IP 的获取顺序
如果服务部署在云环境或前端有代理层,$remote_addr 默认是上一跳地址,必须显式还原为用户真实 IP,否则所有地理映射都无效。
- 在
http块顶部设置可信代理段:
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from 100.64.0.0/10; # CGNAT
real_ip_header X-Forwarded-For;
real_ip_recursive on; - 确保上游代理(如 CDN、ALB)确实设置了
X-Forwarded-For,且只追加、不伪造 - 验证是否生效:临时加一条日志
"XFF: $http_x_forwarded_for, Real: $remote_addr",对比访问时输出
后续使用建议
日志中带地理字段后,可直接对接多种下游系统:
- 写入 Elasticsearch:用 Ingest Pipeline 补充
geo_point字段(如geoip.location = [lon, lat]),Kibana Maps 即可渲染热力图 - 导入 ClickHouse / Prometheus + Grafana:按
country或city维度聚合 PV/UV/错误率 - 用于 Nginx 限流或访问控制:
limit_req zone=percountry burst=10 nodelay if=$geoip2_data_country_code = "CN";











