有时候我们想屏蔽某个地区的 IP 访问,或者根据访问来源转向不同的子站实现分流,此时如果用防火墙规则把 IP 重定向到预定页面并不是特别灵活的办法,特别是一个 IP 上拥有运行多个站点的情况下,正统的办法应该是用 GeoIP 配合对应的 web 服务器模块来实现需求,比如:Apache + Mod_GeoIp 或者 Nginx + Http_GeoIp_Module 等。
以下以 Nginx + GeoIP 为例,已预装 Nginx,基于宝塔(CentOS 7)
# yum install epel-release -y # yum install geoip-devel -y
Ubuntu:
apt-get install libgeoip-dev
# nginx version: nginx/1.10.3 ...... configure arguments: --user=www --group=www --prefix=/www/server/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-stream --with-stream_ssl_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --add-module=/www/server/nginx/src/src/incubator-pagespeed-ngx-1.13.35.2-stable --add-module=/www/server/nginx/src/src/ngx_brotli
要启用 GeoIP 模块只需要在编译参数后面加上 --with-http_geoip_module 即可
# cd /www/server/nginx/src/ # ./configure --user=www --group=www --prefix=/www/server/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-stream --with-stream_ssl_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --add-module=/www/server/nginx/src/src/incubator-pagespeed-ngx-1.13.35.2-stable --add-module=/www/server/nginx/src/src/ngx_brotli --with-http_geoip_module # service nginx stop # make && make install # service nginx start
要验证是否成功启用模块,可以使用如下命令:
# ldd /www/server/nginx/sbin/nginx ...... libGeoIP.so.1 => /lib64/libGeoIP.so.1 (0x00007f9f080d9000) ......
有显示如上字样说明安装成功。
# ls /usr/share/GeoIP/ GeoIP.dat GeoIP-initial.dat GeoIPv6.dat GeoIPv6-initial.dat
找到数据库文件后,就要修改 nginx 配置,在 http 段增加:
# vim /www/server/nginx/conf/nginx.conf ...... # 配置一个即可; geoip_country /usr/share/GeoIP/GeoIP.dat; # geoip_city /usr/share/GeoIP/GeoLiteCityv6.dat; ...... # nginx -t nginx: the configuration file /www/server/nginx/conf/nginx.conf syntax is ok nginx: configuration file /www/server/nginx/conf/nginx.conf test is successful # service nginx reload Reload service nginx... done
由于 IP 广播泛滥,所以 GeoIP 并不是那么准确,如果觉得 GeoIP 库太旧了,可以自行到官网下载最新版,将上述配置的路径改一下即可
GeoIP:仅 IPv4 国家
GeoIPv6:仅 IPv4+IPv6 国家
GeoLiteCity:IPv4 国家 + 省份 + 城市
GeoLiteCityIpv6:IPv4 及 IPv6 国家 + 省份 + 城市
GeoIP 官方下载页GeoIP2 官方下载页
$geoip_country_code; - 国家名的前两个字母, 如, "RU", "US"; $geoip_country_code3; - 国家名的前三个字母, 如, "RUS", "USA"; $geoip_country_name; - 国家名称, 如, "Russian Federation", "United States";
使用 GeoLiteCity 数据库
$geoip_city_country_code; -国家名的前两个字母, 如, "RU", "US"; $geoip_city_country_code3; - 国家名的前三个字母, 如, "RUS", "USA"; $geoip_city_country_name; -国家名称, 如, "Russian Federation", "United States"; $geoip_region; - 省,州或区名 (province, region, state, province, federal land, and the like), 如, "Moscow City", "DC"; $geoip_city; - 城市名称, 如, "Moscow", "Washington"; $geoip_postal_code; - 邮政编号;
# vim /www/server/nginx/conf/vhost/test.conf ...... location / { default_type text/html; charset utf-8; if ( $geoip_country_code = CN ) { return 502 "无权访问!"; } } ......
注:注意空格,少了会报错。
屏蔽城市
使用 GeoLiteCity 数据库
# vim /www/server/nginx/conf/vhost/test.conf ...... location / { default_type text/html; charset utf-8; if ( $geoip_city = Beijing ) { return 502 "无权访问!"; } } ......
注:城市列表可参考官方 CSV 文档
屏蔽省份
使用 GeoLiteCity 数据库
# vim /www/server/nginx/conf/vhost/test.conf ...... location / { default_type text/html; charset utf-8; if ( $geoip_region = 22 ) { return 502 "无权访问!"; } } ......
注:实际测试发现屏蔽省份不能使用说明中的 Beijing、Guangdong 等字眼,需要使用 ISO 3166 规定的代码,代码参见:官方 CSV 文档。
但与此同时又产生一个让人不解的问题,二位数字代码不是唯一的,比如本例中的 22,既可表示 Beijing,又可表示 Goycay,GeoIP 如何保证对应呢?
本文由 podipod软库网 作者:DevOps 发表,转载请注明来源!