nginx GeoIP2的安装使用

2022年8月30日

nginx GeoIP2的安装使用
GeoIP2  可以编译安装 ,也可以apt libnginx-mod-stream-geoip2

# 宿主机系统
$ uname -a
113-Ubuntu SMP Thu Feb 3 18:43:29 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/issue
Ubuntu 18.04.6 LTS \n \l


# 应用软件
nginx-1.22.0.tar.gz
libmaxminddb-1.6.0.tar.gz
ngx_http_geoip2_module-3.4.tar.gz
GeoLite2-City_20220802.tar.gz
GeoLite2-Country_20220802.tar.gz


libmaxminddb 下载
描述: 首先安装 libmaxminddb 库,其提供了一个用于读取MaxMind DB文件的C库,包括来自MaxMind的GeoIP2数据库。这是一种自定义二进制格式,旨在促进 IP 地址的快速查找,同时允许在与地址关联的数据类型方面具有极大的灵活性。

项目地址: https://github.com/maxmind/libmaxminddb
下载构建:

wget -c https://github.com/maxmind/libmaxminddb/releases/download/1.6.0/libmaxminddb-1.6.0.tar.gz
tar -zxvf libmaxminddb-1.6.0.tar.gz && cd libmaxminddb-1.6.0
./configure
make && make install
tee -a /etc/ld.so.conf.d/libc.conf <<'EOF'
# libc default configuration
/usr/local/lib
EOF
sudo ldconfig

或使用apt命令进行安装:

$ sudo apt update
$ sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin geoipupdate

上面安装的软件包是:

libmaxminddb0 libmaxminddb-dev – MaxMind 地理定位数据库

mmdb-bin – 二进制。从命令行调用的程序。使用此命令手动定位 IP。

geoipupdate – 帮助配置和更新 GeoIP2 / GeoLite2 的软件包。

ngx_http_geoip2_module 下载
描述: 下载 ngx_http_geoip2_module 使用基于客户端 IP(默认)或特定变量(同时支持 IPv4 和 IPv6)的 maxmind geoip2 数据库中的值创建变量,该模块现在支持nginx流,并且可以以与http模块相同的方式使用。

项目地址: https://github.com/leev/ngx_http_geoip2_module/
下载构建:

wget https://github.com/leev/ngx_http_geoip2_module/archive/refs/heads/master.zip
unzip master.zip  && ls ngx_http_geoip2_module/
  # config  LICENSE  ngx_http_geoip2_module.c  ngx_stream_geoip2_module.c  README.md

Geoip2 模块语法

geoip2 /usr/local/src/GeoIP2/GeoLite2-Country/GeoLite2-Country.mmdb {
        auto_reload 5m;
        $geoip2_country_code default=unknow source=$http_x_forwarded_for country iso_code;
        $geoip2_country_name default=unknow source=$http_x_forwarded_for country names en;
    }

    geoip2 //usr/local/src/GeoIP2/GeoLite2-City/GeoLite2-City.mmdb {
        $geoip2_data_city_name default=unknow source=$http_x_forwarded_for city names en;
        $geoip2_data_city_subdivisions default=unknow source=$http_x_forwarded_for subdivisions 0 names en;
    }


参数说明:

auto_reload <interval>: 启用自动重新加载将使 nginx 以指定的时间间隔检查数据库的修改时间,如果发生更改则重新加载。

$variable_name [default=

mmdblookup 命令
描述: 在前面编译安装libmaxminddb库后,我们便可以使用 mmdblookup 工具,查找所需数据的路径(例如:国家/地区名称),以JSON格式返回的,其中continent(洲) 、country (国家) 、registered_country(已注册的国家)对象包含了code/geoname_id/names键:

GeoLite2-Country.mmdb 库只带有 country 相关数据样本输出

mmdblookup  --file  /usr/local/src/GeoIP2/GeoLite2-Country/GeoLite2-Country.mmdb --ip  221.226.186.102

    "continent":
      {
        "code":
          "AS" <utf8_string>
        "geoname_id":
          6255147 <uint32>
        "names":
          {
            "de":
              "Asien" <utf8_string>
            "en":
              "Asia" <utf8_string>
            "es":
              "Asia" <utf8_string>
            "fr":
              "Asie" <utf8_string>
            "ja":
              "アジア" <utf8_string>
            "pt-BR":
              "Ásia" <utf8_string>
            "ru":
              "Азия" <utf8_string>
            "zh-CN":
              "亚洲" <utf8_string>
          }
      }
    "country":
      {
        "geoname_id":
          1814991 <uint32>
        "iso_code":
          "CN" <utf8_string>
        "names":
          {
            "de":
              "China" <utf8_string>
            "en":
              "China" <utf8_string>
            "es":
              "China" <utf8_string>
            "fr":
              "Chine" <utf8_string>
            "ja":
              "中国" <utf8_string>
            "pt-BR":
              "China" <utf8_string>
            "ru":
              "Китай" <utf8_string>
            "zh-CN":
              "中国" <utf8_string>
          }
      }
    "registered_country":
      {
        "geoname_id":
          1814991 <uint32>
        "iso_code":
          "CN" <utf8_string>
        "names":
          {
            "de":
              "China" <utf8_string>
            "en":
              "China" <utf8_string>
            "es":
              "China" <utf8_string>
            "fr":
              "Chine" <utf8_string>
            "ja":
              "中国" <utf8_string>
            "pt-BR":
              "China" <utf8_string>
            "ru":
              "Китай" <utf8_string>
            "zh-CN":
              "中国" <utf8_string>
          }
      }
  }


GeoLite2-City.mmdb 库带有 country City 相关数据样本输出 (一般推荐使用该库)

 mmdblookup  --file  /usr/local/src/GeoIP2/GeoLite2-City/GeoLite2-City.mmdb  --ip  221.226.186.102

    "city":
      {
        "geoname_id":
          1799962 <uint32>
        "names":
          {
            "de":
              "Nanjing" <utf8_string>
            "en":
              "Nanjing" <utf8_string>
            "es":
              "Nankín" <utf8_string>
            "fr":
              "Nankin" <utf8_string>
            "ja":
              "南京市" <utf8_string>
            "pt-BR":
              "Nanquim" <utf8_string>
            "ru":
              "Нанкин" <utf8_string>
            "zh-CN":
              "南京" <utf8_string>
          }
      }
    "continent":
      {
        "code":
          "AS" <utf8_string>
        "geoname_id":
          6255147 <uint32>
        "names":
          {
            "de":
              "Asien" <utf8_string>
            "en":
              "Asia" <utf8_string>
            "es":
              "Asia" <utf8_string>
            "fr":
              "Asie" <utf8_string>
            "ja":
              "アジア" <utf8_string>
            "pt-BR":
              "Ásia" <utf8_string>
            "ru":
              "Азия" <utf8_string>
            "zh-CN":
              "亚洲" <utf8_string>
          }
      }
    "country":
      {
        "geoname_id":
          1814991 <uint32>
        "iso_code":
          "CN" <utf8_string>
        "names":
          {
            "de":
              "China" <utf8_string>
            "en":
              "China" <utf8_string>
            "es":
              "China" <utf8_string>
            "fr":
              "Chine" <utf8_string>
            "ja":
              "中国" <utf8_string>
            "pt-BR":
              "China" <utf8_string>
            "ru":
              "Китай" <utf8_string>
            "zh-CN":
              "中国" <utf8_string>
          }
      }
    "location":
      {
        "accuracy_radius":
          50 <uint16>
        "latitude":
          32.058900 <double>
        "longitude":
          118.773800 <double>
        "time_zone":
          "Asia/Shanghai" <utf8_string>
      }
    "registered_country":
      {
        "geoname_id":
          1814991 <uint32>
        "iso_code":
          "CN" <utf8_string>
        "names":
          {
            "de":
              "China" <utf8_string>
            "en":
              "China" <utf8_string>
            "es":
              "China" <utf8_string>
            "fr":
              "Chine" <utf8_string>
            "ja":
              "中国" <utf8_string>
            "pt-BR":
              "China" <utf8_string>
            "ru":
              "Китай" <utf8_string>
            "zh-CN":
              "中国" <utf8_string>
          }
      }
    "subdivisions":
      [
        {
          "geoname_id":
            1806260 <uint32>
          "iso_code":
            "JS" <utf8_string>
          "names":
            {
              "en":
                "Jiangsu" <utf8_string>
              "fr":
                "Province de Jiangsu" <utf8_string>
              "zh-CN":
                "江苏省" <utf8_string>
            }
        }
      ]
  }


GeoLite2-Country.mmdb 与 GeoLite2-Country.mmdb 对比。

# - 国家 ./GeoLite2-Country.mmdb 库
# 如果此时我只想获取 country 的名称可以这样。
$ mmdblookup --file ./GeoLite2-Country.mmdb --ip 221.226.186.102 country names zh-CN
  "中国" <utf8_string>
# 当然如果你想获取国家的 iso_code 也是同样的。
$ mmdblookup --file ./GeoLite2-Country.mmdb --ip 221.226.186.102 country iso_code
  "CN" <utf8_string>

# - 国家、城市库 ./GeoLite2-Country.mmdb 库
$ mmdblookup --file ./GeoLite2-City.mmdb --ip 221.226.186.102 country names zh-CN
  "中国" <utf8_string>
$ mmdblookup --file ./GeoLite2-City.mmdb --ip 221.226.186.102 country iso_code
  "CN" <utf8_string>
$ mmdblookup --file ./GeoLite2-City.mmdb --ip 221.226.186.102 continent names zh-CN
  "亚洲" <utf8_string>
$ mmdblookup --file ./GeoLite2-City.mmdb --ip 221.226.186.102 subdivisions 0 names zh-CN
  "浙江省" <utf8_string>
$ mmdblookup --file ./GeoLite2-City.mmdb --ip 221.226.186.102 subdivisions 0 names iso_code
  "ZJ" <utf8_string>
$ mmdblookup --file ./GeoLite2-City.mmdb --ip 221.226.186.102 city names zh-CN
  "杭州" <utf8_string>
$ mmdblookup --file ./GeoLite2-City.mmdb --ip 221.226.186.102 location longitude # 经度
  120.161200 <double>
$ mmdblookup --file ./GeoLite2-City.mmdb --ip 221.226.186.102 location latitude  # 纬度
  30.299400  <double>
$ mmdblookup --file ./GeoLite2-City.mmdb --ip 221.226.186.102 location time_zone # 时区
  "Asia/Shanghai" <utf8_string>

上述的两个示例我们可以将其转换为 geoip2 模块定义的nginx变量。

# 如只需要国家信息建议使用该库
geoip2 /usr/local/GeoIP2/GeoLite2-Country.mmdb {
  $geoip2_data_country "default=China" source=$remote_addr country names en
}

# 如需要获取国家以及省份信息建议使用该库,此处暂不演示使用,在后续实践中再进行介绍和使用。

geoip2 /usr/local/GeoIP2/GeoLite2-City.mmdb {
  $geoip2_data_country "default=中国" source=$remote_addr country names zh-CN;  # 中国
  $geoip2_data_country_code country iso_code;                  # CN
  $geoip2_data_country_continent continent names zh-CN;        # 亚洲
  $geoip2_data_country_continent_code continent code;          # AS
  $geoip2_data_province_name subdivisions 0 names zh-CN;       # 浙江省
  $geoip2_data_province_isocode subdivisions 0 names iso_code; # "ZJ"
  $geoip2_data_city city names zh-CN;                         # 杭州
  $geoip2_data_city_longitude location longitude;              # 120.161200
  $geoip2_data_city_latitude location latitude;                # 30.299400
  $geoip2_data_city_time_zone location time_zone;             # "Asia/Shanghai"
}

温馨提示: 当请求来自受信任的地址时,将使用“X-Forwarded-For”请求标头字段中的地址, 并且设置 geoip2_proxy_recursive < on | off > 指令。

如果递归搜索被禁用,那么将使用“X-Forwarded-For”中发送的最后一个地址,而不是与一个受信任地址匹配的原始客户端地址。

如果启用了递归搜索,那么将使用“X-Forwarded-For”中发送的最后一个非信任地址,而不是与可信地址之一匹配的原始客户端地址。

模块使用参考地址:https://github.com/leev/ngx_http_geoip2_module/#example-usage

Geoip2 模块编译动态链接库
描述: 有可能此时你通过源码编译方式安装 Nginx 了 ,那如何加入新的Nginx模块呢?

答: 那就是重新编译 Nginx 即可,我们不需要执行make install重新安装 Nginx 具体操作 不在本文记录 请参照 11111


GeoLite2 数据库下载
描述: Nginx 的 ngx_*_geoip2_module 模块依赖于 GeoLite2 数据库, 免费的 GeoLite2 数据库可从 Maxminds 网站获得(需要注册),GeoLite2 数据库基于 IP 地址的数据库和 Web 服务,提供有关地理位置、人口统计和用户以及匿名者的数据。

如果你想下载与更新 GeoLite2 数据库,您需要拥有 MaxMind 帐户 ID 和许可证密钥, 并且当我们在 nginx 中使用则该 GeoIP2 模块,在我们请求时Nginx时根据IP地址来识别来源国家城市,但是我们需要提前下载载该数据库.

简单流程: 首先访问 Maxminds 官网,然后注册登陆到用户后台,创建并获取 License Key, 最后下载 GeoLite2 数据库该压缩包,里面包含的是二进制mmdb格式的库文件。

Maxminds 官网地址: https://maxmind.com
下载 GeoLite2-ASN_20220830.tar.gz
下载 GeoLite2-City_20220830.tar.gz
下载 GeoLite2-Country_20220830.tar.gz

将其上传至服务器并建立目录 一般有City 就够了;
示例:

mkdir   /usr/local/src/GeoIP2/
mv  GeoLite2*   /usr/local/src/GeoIP2/
cd  /usr/local/src/GeoIP2/
tar zxf  GeoLite2-City_20220830.tar.gz
tar zxf  GeoLite2-Country_20220830.tar.gz
mv  GeoLite2-City_20220830 GeoLite2-City
mv  GeoLite2-Country_20220830  GeoLite2-Country

文件也可以放在一个目录中 ,  我们需要的仅仅是 *.mmdb

mv  GeoLite2-City_20220830/GeoLite2-City.mmdb  ./
mv  GeoLite2-Country_20220830/GeoLite2-Country.mmdb ./

Nginx 添加好 GeoIP2 模块后 ,验证GeoIP模块部署环境 ;

如果 apt 安装  则 Load  相应 so
# -- : 加载 geoip2 模块动态链接库

load_module modules/ngx_http_geoip2_module.so;
load_module modules/ngx_stream_geoip2_module.so;

如果编译安装 ,不需要添加模块动态链接库

vim  fastcgi.conf  添加几个变量

fastcgi_param COUNTRY_CODE $geoip2_data_country_code;
fastcgi_param COUNTRY_NAME $geoip2_data_country_name;
fastcgi_param CITY_NAME    $geoip2_data_city_name;


Nginx 配置文件示例

http {
    ...
    # -- 关键点: 日志格式
    log_format demo '$remote_addr - [ $geoip2_country_code $geoip2_data_city_name ] - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for" rt=$request_time urt=$upstream_response_time';    ####  GeoIP2  模块加载  Country 其实可以不使用 City 设置就好
   #geoip2 /usr/local/src/GeoIP2/GeoLite2-Country/GeoLite2-Country.mmdb {
   #     auto_reload 5m;
   #     $geoip2_country_code default=unknow source=$http_x_forwarded_for country iso_code;
   #     $geoip2_country_name default=unknow source=$http_x_forwarded_for country names en;
   # }  

geoip2 //usr/local/src/GeoIP2/GeoLite2-City/GeoLite2-City.mmdb {
        $geoip2_country_code default=unknow source=$http_x_forwarded_for country iso_code;
        $geoip2_country_name default=unknow source=$http_x_forwarded_for country names en;
        $geoip2_data_city_name default=unknow source=$http_x_forwarded_for city names en;
        $geoip2_data_city_subdivisions default=unknow source=$http_x_forwarded_for subdivisions 0 names en;
        $geoip2_data_province_name subdivisions 0 names en;
        $geoip2_data_province_isocode subdivisions 0 iso_code;
        $geoip2_continent_code continent code;
    }
    ...
}


nginx -t   验证是否 OK

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful


实践使用 GeoIP2

1.使用GeoIP2模块请求客户端的IP地址国家省份经纬度展示
描述: 本次实践将根据请求者的国家显示中文或者英文的IP地址位置等相关信息在网页上,通过前面的学习,我们知道 geoip2 在检索有关 geoip 数据库的元数据时,其语法格式为 $variable_name metadata <field>,

实践流程

Step 1.编辑Nginx.conf主配置文件在 http 片段中,自定义定义访问日志格式后加入如下两个 geoip2 指令片段。

http {
  .....
  geoip2 /usr/local/GeoIP2/GeoLite2-Country.mmdb {
    # 启用自动重新加载将使 nginx 以指定的时间间隔检查数据库的修改时间,如果发生更改则重新加载。
    auto_reload 7d;
    $geoip2_country_code country names en;
  }

  geoip2 /usr/local/GeoIP2/GeoLite2-City.mmdb {
    # 中国IP访问都显示中文
    $geoip2_data_country "default=中国" source=$remote_addr country names zh-CN;  # 中国
    $geoip2_data_country_code country iso_code;                  # CN
    $geoip2_data_country_continent continent names zh-CN;        # 亚洲
    $geoip2_data_country_continent_code continent code;          # AS
    $geoip2_data_province_name subdivisions 0 names zh-CN;       # 浙江省
    $geoip2_data_province_isocode subdivisions 0 names iso_code; # "ZJ"
    $geoip2_data_city city names zh-CN;                          # 杭州
    $geoip2_data_city_longitude location longitude;              # 120.161200
    $geoip2_data_city_latitude location latitude;                # 30.299400
    $geoip2_data_city_time_zone location time_zone;              # "Asia/Shanghai"

    # 中国以外的访问都是显示英文
    $geoip2_data_country_en "default=United States" source=$remote_addr country names en;  # United States
    $geoip2_data_country_code country iso_code;                     # US
    $geoip2_data_country_continent_en continent names en;           # North America
    $geoip2_data_country_continent_code continent code;             # NA
    $geoip2_data_province_name_en subdivisions 0 names en;          # ""
    $geoip2_data_province_isocode subdivisions 0 names iso_code;    # ""
    $geoip2_data_city city names en;                                # 杭州
    $geoip2_data_city_longitude location longitude;                 # 120.161200
    $geoip2_data_city_latitude location latitude;                   # 30.299400
    $geoip2_data_city_time_zone location time_zone;                 # "Asia/Shanghai"
  }
  ....

  map $geoip2_data_country_code $CN {
    CN yes;
    TW yes;
    HK yes;
    MO yes;
    default no;
  }


}
Step 2.同样编辑conf.d/demo.conf, 此处使用虚拟主机头(demo.weiyigeek.top)做演, 加入如下指令片段,其主要作用是根据区其地区,使用中英文显示请求者IP地理位置信息。

$ vim conf.d/demo.conf
server {
  ...
  # 精准匹配
  location = /api/v1/ip {
    # 当访问者IP来自 `CN|TW|HK|MO` 时将会以json的形式进行返回中文的IP地址信息。
    if ( $geoip2_data_country_code ~* (CN|TW|HK|MO) ){
      rewrite (.*)  /api/v1/ip/cn last;
    }
    rewrite (.*) /api/v1/ip/en last;
  }

  # 中文显示
  location /api/v1/ip/cn {
    default_type application/json;
    return 200 '{"ip":"$remote_addr","country":{"name": "$geoip2_data_country", "iso_code":  "$geoip2_data_country_code", "continent": "$geoip2_data_country_continent","continent_code": "$geoip2_data_country_continent_code"},"province":{"name":"$geoip2_data_province_name","iso_code":"$geoip2_data_province_isocode"},"city":{"name":"$geoip2_data_city","timezone":"$geoip2_data_city_time_zone"},"location":{"longitude":"$geoip2_data_city_longitude","latitude":"$geoip2_data_city_latitude"}}';
  }

  # 英文显示
  location /api/v1/ip/en {
    default_type application/json;
    return 200 '{"ip":"$remote_addr","country":{"name": "$geoip2_data_country_en", "iso_code":  "$geoip2_data_country_code", "continent": "$geoip2_data_country_continent_en","continent_code": "$geoip2_data_country_continent_code"},"province":{"name":"$geoip2_data_province_name_en","iso_code":"$geoip2_data_province_isocode"},"city":{"name":"$geoip2_data_city","timezone":"$geoip2_data_city_time_zone"},"location":{"longitude":"$geoip2_data_city_longitude","latitude":"$geoip2_data_city_latitude"}}';
  }
  ....
}
Step 3.配置 nginx 核验与重载 nginx 服务, 此处使用不同的网络使用浏览器进行访问https://demo.weiyigeek.top/api/v1/ip验证, 结果如下图所示:。


2.使用GeoIP2模块静止某一国家地区的IP地址访问网站
描述: 为了减少国外的攻击,我们可以将指定的地区IP访问进行放行,除此之外的全部拒绝。

实际流程:

Step 1.在 nginx.conf 中添加 map 指令并进行如下配置, 预定义了可以访问网站的地区。

http {
....
$geoip2_data_country_code $allow_visit {
    CN yes;
    TW yes;
    HK yes;
    MO yes;
    default no;
}
....
}
温馨提示:

map 指令是由ngx_http_map_module模块提供的,默认情况下安装 nginx 都会安装该模块.

map 的主要作用是'创建自定义变量',通过使用 nginx 的'内置'变量,去'匹配'某些特定规则; 如果匹配成功则设置某个值给自定义变量,而这个'自定义变量'又可以'用作他用'。

Step 2.在demo.conf配置文件中添加一个访问验证的示例。

# 访问该页面如果$allow_visit变量不为yes则返回403页面,否则返回访问者的IP地区信息。
location /allow/html {
  default_type text/html;
  if ($allow_visit != yes ) {
    return 403 "IP [ $remote_addr ] 禁止访问! <br> $remote_addr - $geoip2_data_country - $geoip2_data_country_code - $geoip2_data_country_continent";
  }
  return 200 "欢迎IP为 [ $remote_addr ] 用户进行访问! <br> $remote_addr - $geoip2_data_country - $geoip2_data_country_code - $geoip2_data_country_continent";
}
Step 3.同样修改完成后,我们需要针对nginx配置核验与重新加载配置 nginx -t && nginx -s reload (PS: 后续将不再提示了,想必大家都聊熟于心了), ,之后分别使用工具进行访问验证,结果如下所示。

3.使用GeoIP2模块实现不同国家访问进入不同目录页面
描述: 在某些时刻我们可能会对不同地区来源访问的客户展示不同的页面,例如国内我就显示中文的页面,而新加坡我就显示英文的页面,这样一来就更加人性化一点。

示例演示
在/usr/local/nginx/html目录中创建ch/en子目录,同时准备两个不同地区访问的测试页面:

$ tree /usr/local/nginx/html
├── ch
│   └── index.html
├── en
│   └── index.html


$ cat ch/index.html
<h1>中文站点</h1>
<iframe src="https://blog.weiyigeek.top" frameborder="0" width="500"></iframe>
Nginx 配置中使用GeoIP处理访问请求。

http {
....
  map $geoip2_data_country_code $lang_ch {
    CN yes;
    TW yes;
    HK yes;
    MO yes;
    default no;
  }
....
 server {
    listen       80;
    server_name  demo.weiyigeek.top;
    location / {
      set $rootpath html/ch; # 关键点设置一个根目录变量。
      if ($lang_ch = no) {
        set $rootpath html/en;
      }
      add_header program-path $rootpath; # 关键点写入到响应头中。
      add_header country-code $geoip2_data_country_code;
      root $rootpath;
      index index.html index.htm;
    }
  }
}


https://blog.csdn.net/u013072756/article/details/126204281
https://blog.csdn.net/qq522044637/article/details/122703038
http://t.zoukankan.com/lsgxeva-p-8133886.html

没有评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注