mod_setenvif无法直接识别地理位置,需先由mod_maxminddb等模块解析ip为国家码并设为环境变量,再用setenvif基于该变量打标签,最后在日志、访问控制或代理路由中显式引用这些标签实现差异化逻辑。

mod_setenvif 本身不能识别地理位置,它只能对已存在的请求属性做条件匹配。要实现“根据地理位置触发差异化逻辑”,必须分两步:先由地理模块(如 mod_maxminddb)把 IP 解析为国家码等变量,再用 SetEnvIf 基于这些变量打标签,最后在日志、访问控制或代理路由中使用这些标签。
第一步:让 Apache 知道用户来自哪国
Apache 不自带 IP 地理查询能力。你需要加载 mod_maxminddb(推荐)或 mod_geoip2,并配置 GeoLite2 数据库:
- 启用模块:a2enmod maxminddb(Ubuntu/Debian)或确保 LoadModule maxminddb_module modules/mod_maxminddb.so 已写入配置
- 指定数据库路径和注入的环境变量名,例如:
MaxMindDBEnable On
MaxMindDBFile GEOIP_COUNTRY_DB /usr/share/GeoIP/GeoLite2-Country.mmdb
MaxMindDBEnv GEOIP_COUNTRY_CODE COUNTRY_ISO_CODE - 重启 Apache 后,每个请求都会自动拥有 GEOIP_COUNTRY_CODE 变量,值如 CN、US、JP
第二步:用 SetEnvIf 给地域打上可读标签
有了 GEOIP_COUNTRY_CODE,就可以用 SetEnvIf 定义语义化环境变量:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 匹配中国及港澳台:SetEnvIf GEOIP_COUNTRY_CODE ^(CN|HK|TW) is_china_region
- 匹配东南亚国家:SetEnvIf GEOIP_COUNTRY_CODE ^(TH|VN|MY|ID|SG) is_sea_region
- 匹配内部办公网段(可叠加):SetEnvIf Remote_Addr ^10\.100\.|^172\.16\. is_internal
- 注意:变量名不要含连字符;ISO 码全大写;正则末尾不加 i 标志(标准码本身就是大写)
第三步:用标签驱动实际差异化行为
设好环境变量后,必须显式调用才能生效。常见用途有三类:
-
日志标记:在 LogFormat 中引用,例如
LogFormat "%h %l %u %t \"%r\" %>s %b %{is_china_region}e %{is_sea_region}e" geo_log
再配合 CustomLog logs/access_geo.log geo_log,方便后续按区域分析流量 -
访问控制:比如只允许中国区用户访问后台
Require env is_china_region
-
反向代理分流:结合 mod_proxy,将请求转给不同后端集群
RewriteCond %{ENV:is_china_region} ^1$
RewriteRule ^/api/(.*)$ http://shenzhen-api/$1 [P]
RewriteCond %{ENV:is_sea_region} ^1$
RewriteRule ^/api/(.*)$ http://singapore-api/$1 [P]
关键提醒:不是设了就自动起作用
SetEnvIf 只是“贴标签”,不会自动拦截、转发或改写响应。所有后续动作都依赖其他模块显式引用这些变量。另外,这些规则应放在 VirtualHost 或主配置中,避免放在 .htaccess 里——后者权限受限且性能较差。若用到了 mod_rewrite,注意 SetEnvIf 必须在 rewrite 规则之前执行,否则可能取到重写后的 URI 而非原始值。









