17.基于IP地理位置配置访问规则
使用 GeoIP2 动态模块,根据客户端的地理位置控制访问或将流量转发到不同的upstream服务器。
开源版NGINX 使用GeoLite2数据库来匹配用户的IP地址及其位置。
GeoIP2或GeoLite2数据库可以从MaxMind下载页面获得。在此示例中,使用 GeoLite2 免费下载数据库。
要获取和解压缩 GeoLite2 国家/地区数据库,请执行以下操作:
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz
gunzip GeoLite2-Country.mmdb.gz
要获取和解压缩GeoLite2 City数据库,请执行以下操作:
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
gunzip GeoLite2-City.mmdb.gz
了解数据库结构(Understanding Database Structure)
要查看可用的地理数据,您可以使用 mmdblookup 实用程序查询 GeoLite2-Country 和 GeoLite2-City 数据库。地理数据表示为 JSON 树。
安装 libmaxminddb 数据库实用程序:
- 对于 Amazon Linux、CentOS、Oracle Linux 和 RHEL:
yum install libmaxminddb-devel
可以按以下格式发送对数据库的查询:
mmdblookup –file [FILE PATH] –ip [IP ADDRESS] [DATA PATH]
例如,要获取 IP 地址的所有可用地理数据,请发送以下命令:8.8.8.8
mmdblookup --file /usr/local/etc/geoip2/GeoLite2-Country.mmdb --ip 8.8.8.8
输出将是:
{
"continent":
{
"code":
"NA" <utf8_string>
"geoname_id":
6255149 <uint32>
"names":
{
"de":
"Nordamerika" <utf8_string>
"en":
"North America" <utf8_string>
"es":
"Norteamérica" <utf8_string>
"fr":
"Amérique du Nord" <utf8_string>
"ja":
"北アメリカ" <utf8_string>
"pt-BR":
"América do Norte" <utf8_string>
"ru":
"Северная Америка" <utf8_string>
"zh-CN":
"北美洲" <utf8_string>
}
}
"country":
{
"geoname_id":
6252001 <uint32>
"iso_code":
"US" <utf8_string>
"names":
{
"de":
"USA" <utf8_string>
"en":
"United States" <utf8_string>
"es":
"Estados Unidos" <utf8_string>
"fr":
"États-Unis" <utf8_string>
"ja":
"アメリカ合衆国" <utf8_string>
"pt-BR":
"Estados Unidos" <utf8_string>
"ru":
"США" <utf8_string>
"zh-CN":
"美国" <utf8_string>
}
}
"registered_country":
{
"geoname_id":
6252001 <uint32>
"iso_code":
"US" <utf8_string>
"names":
{
"de":
"USA" <utf8_string>
"en":
"United States" <utf8_string>
"es":
"Estados Unidos" <utf8_string>
"fr":
"États-Unis" <utf8_string>
"ja":
"アメリカ合衆国" <utf8_string>
"pt-BR":
"Estados Unidos" <utf8_string>
"ru":
"США" <utf8_string>
"zh-CN":
"美国" <utf8_string>
}
}
}
要获取特定的地理数据,例如,仅获取特定国家/地区的 ISO 代码,请将参数添加到命令末尾:country iso_code
mmdblookup --file /usr/local/etc/geoip2/GeoLite2-Country.mmdb --ip 8.8.8.8 country iso_code
在NGINX中配置GeoIP2
开源版NGINX不自带GeoIP2模块,需要重新手动编译:
-
获取
geoip2模块源代码: 下载并解压geoip2模块的源代码。你可以从模块的 GitHub 仓库获取:git clone https://github.com/leev/ngx_http_geoip2_module.git将
ngx_http_geoip2_module目录放置在 Nginx 源代码目录的./modules下。 -
配置编译选项: 在 Nginx 源代码目录下执行配置命令,包含
geoip2模块。./configure --add-module=./modules/ngx_http_geoip2_module -
编译和安装: 执行编译和安装命令。
make
make install -
将国家和城市数据库的路径添加到 NGINX 配置中,其中包含
http {}、upstream {}或两者的geoip2 {}块:http {
#...
geoip2 GeoIP2/GeoLite2-Country.mmdb {
#...
}
geoip2 GeoIP2/GeoLite2-City.mmdb {
#...
}
}
stream {
#...
geoip2 GeoIP2/GeoLite2-Country.mmdb {
#...
}
geoip2 GeoIP2/GeoLite2-City.mmdb {
#...
}
} -
基于 GeoIP 数据库结构,创建自定义变量,这些变量将保留 GeoIP2 数据库中的数据,然后将数据传递给地图或 split_clients 指令(可以在
<span> </span>http {}和upstream {}上下文中应用):geoip2 GeoIP2/GeoLite2-City.mmdb {
$geoip2_data_city_name city names en;
$geoip2_data_postal_code postal code;
$geoip2_data_latitude location latitude;
$geoip2_data_longitude location longitude;
$geoip2_data_state_name subdivisions 0 names en;
$geoip2_data_state_code subdivisions 0 iso_code;
}
geoip2 GeoIP2/GeoLite2-Country.mmdb {
$geoip2_data_continent_code continent code;
$geoip2_data_country_iso_code country iso_code;
}
#...
方案:选择最近的服务器(Scenario: Choosing the Nearest Server)
使用来自创建的变量的地理位置数据,可以将客户端连接重定向到最近的服务器,从而减少网络延迟 并提高连接速度。
这可以通过在变量中使用GeoIP2数据库中的大陆(continent)代码来实现,地图模块(map module)将创建另一个变量,该变量的值将是基于大陆位置的最接近的服务器。基于此值,NGINX 会将请求传递给相应的upstream服务器组。
- 确保已为每个大洲配置服务器或upstream服务器组,例如,
eu对于欧洲、na对于北美,all对于 IP 地址无法与 GeoIP 数据库匹配的情况:upstream all {
server all1.example.com:12345;
server all2.example.com:12345;
}
upstream eu {
server eu1.example.com:12345;
server eu2.example.com:12345;
}
upstream na {
server na1.example.com:12345;
server na2.example.com:12345;
} - 添加具有任何名称的变量(例如
$geoip2_data_continent_code)的geoip2 {}块,以获取GeoIP2数据库的大陆代码:geoip2 GeoIP2/GeoLite2-Country.mmdb {
$geoip2_data_continent_code continent code;
}
#... - 创建地图(map)块将创建
$nearest_server变量#...
map $geoip2_data_continent_code $nearest_server {
default all;
EU eu;
NA na;
AS as;
AF af;
}
#... - 创建
server{}块,该块将根据$nearest_server变量中传递的值将请求传递给upstream服务器组之一:server {
listen 12346;
proxy_pass http://$nearest_server;
}
如果大陆是欧洲,那么 的值将是 ,并且连接将通过 proxy_pass 指令传递给上游:$nearest_servereueu
#...
server {
listen 12346;
proxy_pass http://$nearest_server;
}
upstream all {
server all1.example.com:12345;
server all2.example.com:12345;
upstream eu {
server eu1.example.com:12345;
server eu2.example.com:12345;
}
upstream na {
server na1.example.com:12345;
server na2.example.com:12345;
}
#...
示例
# can be either "http {}" or "stream {}"
#...
geoip2 GeoIP2/GeoLite2-Country.mmdb {
$geoip2_data_continent_code continent code;
}
map $geoip2_data_continent_code $nearest_server {
default all;
EU eu;
NA na;
AS as;
AF af;
}
server {
listen 12346;
proxy_pass http://$nearest_server;
}
upstream all {
server all1.example.com:12345;
server all2.example.com:12345;
}
upstream eu {
server eu1.example.com:12345;
server eu2.example.com:12345;
}
upstream na {
server na1.example.com:12345;
server na2.example.com:12345;
}
在此示例中,将在数据库 GeoLite2-Country.mmdb中检查IP地址,结果将写入变量 $geoip2_data_continent_code。NGINX 会将变量的值与map指令中的值进行匹配,并将结果写入自定义变量 $nearest_server中,在我们的示例中。根据 $nearest_server的值,proxy_pass 指令将选择相应的upstream服务器。