应使用 map 在 http 块预定义地域路径变量,配合 try_files 实现安全静态资源分发——先通过 geoip2 加载 GeoLite2 数据库提取国家码,再用 map 映射 $static_root,最后在 location 中用 try_files 按优先级查找 /cn/、/jp/、/en/ 下资源。

直接在 location 块里用 if 判断国家码再切换 root,看似简单,实则不可靠——Nginx 官方明确不建议在 location 中大量使用 if,容易引发路径拼接错误、变量作用域混乱,甚至 404 或 500。真正安全高效的做法,是把地域判断提前到 http 块,用 map 构建好变量,再让 location 干净引用。
确保 GeoIP2 正确加载并提取国家码
这是整个流程的前提,必须在 http 块顶部完成:
- 确认已安装
ngx_http_geoip2_module(旧版geoip_country已废弃,混用会报错) - 下载
GeoLite2-Country.mmdb,上传至服务器(如/www/geoip/GeoLite2-Country.mmdb) - 在
nginx.conf的http块开头添加:
$geoip2_data_country_code country iso_code;
$geoip2_data_country_name country names en;
}
用 map 预定义地域路径变量
map 指令必须在 http 或 server 块顶层声明,它把国家码映射成你预设的静态资源路径前缀:
- 例如:中国用户访问
/cn/下资源,日本走/jp/,其余默认走/en/ - 在同一个
http块中添加:
default "/en";
CN "/cn";
JP "/jp";
KR "/kr";
}
这样 $static_root 就成了一个可安全用于 location 的变量,不会因作用域问题失效。
在 location 中通过 try_files 实现路径拼接
不要动态改 root,而是用 try_files 按优先级查找带地域前缀的文件:
- 假设所有静态资源放在
/var/www/site/下,结构为:/var/www/site/cn/index.html、/var/www/site/jp/logo.png等 - 在站点
server块内写:
alias /var/www/site/;
try_files $static_root$uri $static_root$uri/ /en$uri /en$uri/ =404;
}
请求 /logo.png 会依次尝试:/cn/logo.png → /jp/logo.png → /en/logo.png,命中即返回,逻辑清晰且无副作用。
处理真实 IP 与调试验证
如果 Nginx 前有 CDN 或负载均衡,$remote_addr 会变成代理 IP,导致地域识别失败:
- 在
http块添加可信上游网段:set_real_ip_from 103.21.244.0/22;(填你实际 LB 的 CIDR) - 设置头字段解析:
real_ip_header X-Forwarded-For;,必要时加real_ip_recursive on; - 加个测试
location快速验证:
return 200 "$geoip2_data_country_code\n";
}
用 curl http://your-domain.com/geo-test 查看返回值,确认是否拿到正确国家码。

















