map指令必须在http块顶层定义,不能置于server或location中;需用CIDR精确匹配IP段,避免正则;map变量值须与upstream名称完全一致;真实环境须通过set_real_ip_from和real_ip_header处理X-Forwarded-For链路污染。

map 指令必须在 http 块顶层定义,不能放在 server 或 location 里
很多人一上来就在 server 块里写 map,Nginx 直接报错:nginx: [emerg] "map" directive is not allowed here。这是因为 map 是变量映射模块,属于运行时变量生成机制,只能在 http 上下文中初始化。
实操建议:
- 把所有
map块统一放在nginx.conf的http大括号最上方(或单独 include 进来) - 每个
map必须指定源变量(如$remote_addr)和目标变量名(如$backend_group),且目标变量不能已存在 - 匹配顺序从上到下,第一个成功匹配的规则生效;用
default设兜底值,否则未匹配时变量为空字符串——这可能导致 upstream 选型失败
用 CIDR 精确匹配 IP 段,别用正则硬扛
有人试图用 ~ 正则去判断 192.168.10. 开头的地址,结果发现 $remote_addr 可能带端口(IPv6 场景)、可能被代理覆盖、还可能触发重复编译开销。正确做法是用原生 CIDR 语法,Nginx map 对 192.168.0.0/16 这类写法原生支持,无额外性能损耗。
实操建议:
- 优先使用 CIDR 表达式,例如:
114.114.114.0/24、2408:8700::/32 - 国内常见 CDN 回源 IP 段可直接查运营商公开路由表,比如阿里云函数计算回源段是
47.96.0.0/16,腾讯云是101.32.0.0/16 - 如果必须用正则(如匹配某类动态出口 IP),改用
~*不区分大小写,并确保正则足够简短,避免在每次请求时重复执行
map 变量要和 upstream name 对齐,否则 502 就在下一秒
map 本身只负责赋值,真正路由靠 proxy_pass http://$backend_group。如果 $backend_group 的值是 bj_cluster,但 upstream 块叫 upstream beijing,Nginx 启动不报错,但请求一来就是 502 Bad Gateway —— 因为它找不到名为 bj_cluster 的 upstream。
实操建议:
- upstream 名称必须与 map 输出的字符串**完全一致**(包括大小写、下划线、中划线)
- 建议命名风格统一,例如全部小写 + 下划线:
shanghai_cache、guangzhou_origin - 可以在
upstream块里加keepalive 32和least_conn,但不要在 map 里做负载逻辑——map 只管“分组”,不负责“选节点”
真实环境必须处理 X-Forwarded-For 链路污染
线上几乎全是反向代理链路,$remote_addr 拿到的是上一跳 Nginx 或 SLB 的 IP,不是真实用户 IP。直接拿它做地理分流,全国用户都会被分到同一个后端集群。
实操建议:
- 先用
set_real_ip_from明确可信代理网段(如公司内网段、云厂商 LB 段) - 再启用
real_ip_header X-Forwarded-For,让 Nginx 把$remote_addr替换为 header 最左的有效 IP - 验证是否生效:加一行
add_header X-Real-IP $remote_addr;,curl 看响应头;注意某些 CDN 会伪造 XFF,需配合real_ip_recursive on向右递归取最后一个非可信 IP


















