在Nginx中按地区编码区分缓存键,需通过ngx_http_geoip2_module解析IP获取$geoip2_country_code,并在proxy_cache_key中嵌入该变量(建议用map设默认值ZZ),同时支持CDN透传X-Client-Country头以优化性能。

在 Nginx 中实现按地区编码(如 country_code)区分缓存键,关键是在 proxy_cache_key 中嵌入地理信息变量,并确保该变量在请求到达缓存层前已正确解析。Nginx 本身不内置 IP 地理定位,需依赖 ngx_http_geoip2_module(推荐)或旧版 geoip 模块配合 MaxMind 数据库。
1. 安装并配置 GeoIP2 模块获取地区编码
GeoIP2 是当前主流方案,支持 IPv6 和更精准的数据库更新:
- 编译 Nginx 时添加
--add-module=/path/to/ngx_http_geoip2_module - 下载 MaxMind GeoLite2 Country 数据库(
GeoLite2-Country.mmdb),放在安全路径如/usr/share/GeoIP/GeoLite2-Country.mmdb - 在
http块中加载数据库和定义变量:
http {
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
# 可选:补充城市、ASN 等字段
}
<pre class="brush:php;toolbar:false;"># 若使用 CDN 回源,真实客户端 IP 通常在 X-Forwarded-For 或 CF-Connecting-IP 中
# 需先用 map 提取最左非私有 IP(示例以 Cloudflare 为例)
map $http_cf_connecting_ip $real_ip {
"" $remote_addr;
default $http_cf_connecting_ip;
}
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_country_code source=$real_ip country iso_code;
}}
2. 在 proxy_cache_key 中加入地区编码
缓存键必须唯一标识“内容 + 地区”,避免跨区混用。建议包含协议、主机、路径、查询参数和地区码:
- 在
location或server块中配置缓存键,例如:
proxy_cache_key "$scheme$request_method$host$request_uri$geoip2_country_code";
注意:$geoip2_country_code 为空时(如 IP 未匹配或数据库缺失)会导致缓存键不一致。可设默认值提升健壮性:
map $geoip2_country_code $cache_country {
"" "ZZ"; # 未知地区统一用 ZZ
default $geoip2_country_code;
}
# 然后使用 $cache_country 替代 $geoip2_country_code3. 配置缓存策略与验证
启用缓存后需确认地区维度生效:
- 开启缓存日志或使用
$upstream_cache_status响应头观察 HIT/MISS - 用不同地区出口 IP(如通过代理或 Cloudflare Workers 修改
CF-Connecting-IP)发起相同请求,检查响应头中X-Cache是否分别命中 - 若使用 CDN(如 Cloudflare、Akamai),注意其自身边缘缓存可能覆盖 Nginx 缓存;建议将 Nginx 部署在 CDN 后、应用前,作为二级缓存(L2 cache),并在 CDN 设置中禁用对动态路径的缓存,或透传地区头
4. 补充:兼容 CDN 头部透传与回源控制
为确保 CDN 正确传递客户端地区信息给 Nginx:
- 在 CDN 控制台设置「缓存规则」,强制透传
CF-IPCountry(Cloudflare)或自定义头如X-Client-Country - Nginx 中可直接读取该头(比 GeoIP 更快,但依赖 CDN 准确性):
map $http_x_client_country $cache_country {
"" "ZZ";
default $http_x_client_country;
}这种方式跳过本地 GeoIP 查询,降低延迟,适合 CDN 已提供高可信地区标签的场景。











