Nginx配置GeoIP2

背景

  • GeoIP2数据库是免费的IP地理位置数据库,可以通过GeoIP2对不同地域的访问IP自定义不同的响应。GeoIP2分为收费版、免费版,其中免费版准确性要差一些,它的数据库更新频率为每两周一次。对于我这种小网站来讲已经很够用了。
  • GeoIP2的前身是GeoIP,但是GeoIP已经过时了,被GeoIP2所替代。目前官网:https://www.maxmind.com/
  • 搭建步骤简略:
    • 安装libmaxminddb模块
    • 编译安装ngx_http_geoip2_module模块
    • 配置Nginx的ngx_http_geoip2_module模块
    • 配置IP相关请求的处理方式
    • 配置自动更新GeoIP2数据库

搭建

安装libmaxminddb模块

  • 准备编译环境

    1
    2
    sudo apt update
    sudo apt install build-essential -y
  • 通过apt安装libmaxminddb

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 添加更新源
    sudo add-apt-repository ppa:maxmind/ppa
    # 删除更新源
    # sudo add-apt-repository -r ppa:maxmind/ppa

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

    # 安装完成后检查安装结果
    mmdblookup --version
  • **(拓展)**libmaxminddb模块也可以通过源码安装,安装方式如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 拉取最新的源码,链接:https://github.com/maxmind/libmaxminddb/releases
    wget https://github.com/maxmind/libmaxminddb/releases/download/1.3.2/libmaxminddb-1.3.2.tar.gz
    tar xzvf libmaxminddb-1.3.2.tar.gz
    cd libmaxminddb-1.3.2

    # 编译安装源码,需要进入下载的源码所在文件夹中
    ./configure
    make
    make check
    sudo make install
    sudo ldconfig

    # 安装完以后检查一下安装是否成功
    mmdblookup --version

编译安装ngx_http_geoip2_module模块

  • 下载ngx_http_geoip2_module的源码,下载来源路径:https://github.com/leev/ngx_http_geoip2_module/releases

    1
    2
    wget https://github.com/leev/ngx_http_geoip2_module/archive/3.3.tar.gz
    tar xzvf 3.3.tar.gz
  • 下载与当前ubuntu系统中版本相同的nginx源码包

    1
    2
    3
    4
    5
    6
    # 查看当前nginx的版本
    nginx -v

    # 到nginx上下载对应版本的nginx源码
    wget http://nginx.org/download/nginx-1.14.0.tar.gz
    tar xzvf nginx-1.14.0.tar.gz
  • 编译ngx_http_geoip2_module模块。此处需要注意,一定要保持当前正在运行的nginx编译时的参数与本次编译时的参数保持一致

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 安装编译环境,随着版本迭代更新,这块可能会有变化,到时候自寻
    sudo apt update
    sudo apt install libpcre3-dev libssl-dev zlib1g-dev libxml2-dev libxslt1-dev libgd-dev libgeoip-dev -y

    # 查看当前正在运行的nginx的编译参数
    # 其中【configure arguments】后面的内容便全是参数,将其内容全部复制下来
    nginx -V

    # 进入刚下载nginx源码文件夹,进行重新编译
    # 编译时需增加一个编译ngx_http_geoip2_module模块的参数,其路径是之前下载的ngx_http_geoip2_module文件夹路径
    # 添加的参数为:--add-dynamic-module=/root/wu/ngx_http_geoip2_module-3.3
    cd nginx-1.14.0
    # 注意最后一定得添加ngx_http_geoip2_module-3.3得参数
    ./configure --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-mcUg8N/nginx-1.14.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module=/root/dev/ngx_http_geoip2_module-3.3
    make
    make modules
  • 如果在configure的时候发生错误,请根据提示补装相应的依赖关系后进行重新编译。编译完成后可切换到当前nginx文件夹下的objs目录中,就可以寻找到我们想要的两个文件:【ngx_http_geoip2_module.so】和【ngx_stream_geoip2_module.so】,然后将这两个文件移动到【/usr/lib/nginx/modules】路径下

    1
    2
    3
    cd objs
    mv ngx_http_geoip2_module.so /usr/lib/nginx/modules
    mv ngx_stream_geoip2_module.so /usr/lib/nginx/modules
  • (拓展) 如果是通过宝塔面板编译安装的nginx,这种情况就简单一些。根据宝塔默认的安装路径,nginx的源码保存在/www/server/nginx/src,只需切换到该目录下面进行上述的编译工作即可。但这时候不要再下载nginx源码,因为宝塔的nginx编译参数都是需要在这个目录中执行的,防止意外情况发生,我们就在这个目录操作就好了。

配置nginx的ngx_http_geoip2_module模块

  • 下载GeoIP2的相关数据库【包括GeoLite2 City和GeoLite2 County两个库】。现下GeoIP2需要注册用户才能够免费下载GeoLite2的数据库,因此先注册一个用户,之后进入【个人中心】,在左侧【GeoIP2/GeoLite2】中找到【Download File】,进去后下载【gzip】的文件。

    image-20200913064447345

  • 将下载好的【GeoLite2 City】库与【GeoLite2 County】库复制到/var/GeoIP2下使用。这个存放路径可根据需要自己定,只是在配置nginx的时候,需要指定好这两个库文件的具体位置。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 提前创建好文件夹
    mkdir /var/geoip2

    # 解压下载的两个数据库的tar包
    tar -xzvf GeoLite2-City.tar.gz
    tar -xzvf GeoLite2-County.tar.gz
    mv GeoLite2-City_20200908/GeoLite2-City.mmdb /var/geoip2/
    mv GeoLite2-County_20200908/GeoLite2-County.mmdb /var/geoip2/

    # 解压完成后,使用mmdblookup命令在库中测试一下,如果成功则直接返回该IP对应的字典信息
    mmdblookup -f /var/geoip2/GeoLite2-County.mmdb -i 8.8.8.8
  • 配置nginx的配置文件【nginx.conf】,其配置文件路径根据不同的安装方式位于不同的路径之下:

    apt安装:文件位于【/etc/nginx】下

    宝塔面板:文件位于【/www/server/nginx/conf/】下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    # 在nginx.conf文件的头部引入编译的ngx_http_geoip2_module.so
    load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;

    # (参考)同时在其中引入ngx_http_geoip2_module模块的相关配置,配置项都配置在http项中,下面配置仅作参考
    # (参考)注意其对应的GeoLite2-City.mmdb文件的路径为自己存放的路径。
    # (参考)这个配置是一位博主给的,目前还不知道配置的含义,暂且记录。
    geoip2 /var/geoip2/GeoLite2-City.mmdb {
    $geoip2_data_city_continent_code continent code;
    $geoip2_data_city_continent_name continent names zh-CN;
    $geoip2_data_city_country_code country iso_code;
    $geoip2_data_city_country_name country names zh-CN;
    $geoip2_data_city_region_code subdivisions 0 iso_code;
    $geoip2_data_city_region_name subdivisions 0 names zh-CN;
    $geoip2_data_city_location_latitude location latitude;
    $geoip2_data_city_location_longitude location longitude;
    $geoip2_data_city_postal postal code;
    $geoip2_data_city_city_name city names en;
    }

    # (推荐)以下是另一位博主提供的配置方式
    geoip2 /var/GeoIP2/GeoLite2-Country.mmdb {
    auto_reload 60m;
    $geoip2_metadata_country_build metadata build_epoch;
    $geoip2_data_country_code country iso_code;
    $geoip2_data_country_name country names en;
    }

    geoip2 /var/GeoIP2/GeoLite2-City.mmdb {
    auto_reload 60m;
    $geoip2_metadata_city_build metadata build_epoch;
    $geoip2_data_city_name city names en;
    }
  • 配置nginx的配置文件【fastcgi.conf】,用于配置将geo信息传递到php上(如果网站不是php的则可不需要配置),其配置文件路径根据不同的安装方式位于不同的路径之下:

    apt安装:文件位于【/etc/nginx】下

    宝塔面板:文件位于【/www/server/nginx/conf/】下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # (参考)一位博主提供的配置信息
    fastcgi_param MM_CONTINENT_CODE $geoip2_data_city_continent_code;
    fastcgi_param MM_CONTINENT_NAME $geoip2_data_city_continent_name;
    fastcgi_param MM_COUNTRY_CODE $geoip2_data_city_country_code;
    fastcgi_param MM_COUNTRY_NAME $geoip2_data_city_country_name;
    fastcgi_param MM_REGION_CODE $geoip2_data_city_region_code;
    fastcgi_param MM_REGION_NAME $geoip2_data_city_region_name;
    fastcgi_param MM_LATITUDE $geoip2_data_city_location_latitude;
    fastcgi_param MM_LONGITUDE $geoip2_data_city_location_longitude;
    fastcgi_param MM_POSTAL_CODE $geoip2_data_city_postal;
    fastcgi_param MM_CITY_NAME $geoip2_data_city_city_name;

    # (推荐)另一位博主提供的配置信息
    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】

    1
    2
    3
    4
    5
    6
    # 如果没有报异常,则正常重启
    sudo service nginx restart
    # sudo service nginx -s reload

    # 如果报错了,则根据报错内容去修改配置文件
    sudo service nginx status

配置IP相关请求的处理方式

  • 若还拥有ISP的库,则需要在nginx.conf中配置如下:

    1
    2
    3
    4
    5
    # 配置项配置在http项中
    geoip2 /var/geoip2/GeoIP2-ISP.mmdb {
    $geoip2_data_isp_isp isp;
    $geoip2_data_isp_org organization;
    }

    同时若网站基于php,则还需要在nginx.conf中配置如下内容以完成isp信息的读取:

    1
    2
    fastcgi_param MM_ISP $geoip2_data_isp_isp;
    fastcgi_param MM_ORG $geoip2_data_isp_org;
  • 若使用cloudflare加速了自己的网站,此时默认获取的IP其实不是客户端IP,而是cloudflare的cdn服务器IP。这时候在nginx.conf中的代码需要做调整,将source指定为$HTTP_CF_CONNECTING_IP。若用了nginx反向代理,则将serouce指定为$HTTP_X_FORWARDED_FOR。此处配置以加速为例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # 需注意,每处添加了一个source配置项,同时,需注意GeoIP2的数据库地址需准确
    # 此处也只配置City的数据,还可以配置County的数据
    # 内容配置在http配置项中
    geoip2 /var/geoip2/GeoLite2-City.mmdb {
    auto_reload 60m;
    $geoip2_data_city_continent_code source=$HTTP_CF_CONNECTING_IP continent code;
    $geoip2_data_city_continent_name source=$HTTP_CF_CONNECTING_IP continent names zh-CN;
    $geoip2_data_city_country_code source=$HTTP_CF_CONNECTING_IP country iso_code;
    $geoip2_data_city_country_name source=$HTTP_CF_CONNECTING_IP country names zh-CN;
    $geoip2_data_city_region_code source=$HTTP_CF_CONNECTING_IP subdivisions 0 iso_code;
    $geoip2_data_city_region_name source=$HTTP_CF_CONNECTING_IP subdivisions 0 names zh-CN;
    $geoip2_data_city_location_latitude source=$HTTP_CF_CONNECTING_IP location latitude;
    $geoip2_data_city_location_longitude source=$HTTP_CF_CONNECTING_IP location longitude;
    $geoip2_data_city_postal source=$HTTP_CF_CONNECTING_IP postal code;
    $geoip2_data_city_city_name source=$HTTP_CF_CONNECTING_IP city names en;
    }

    # 没有该文件的话就不用配置这一项
    geoip2 /var/geoip2/GeoIP2-ISP.mmdb {
    auto_reload 60m;
    $geoip2_data_isp_isp source=$HTTP_CF_CONNECTING_IP isp;
    $geoip2_data_isp_org source=$HTTP_CF_CONNECTING_IP organization;
    }
  • 若想屏蔽某个国家的访问,则在nginx.conf中配置访问名单,配置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    # 此处配置的内容会被当作变量用于网站访问的路由中
    # 配置的内容放置于http项中
    map $geoip2_data_country_code $domain_xyz_allowed_country {
    default yes;
    # 第一个参数是国家的简称,对应于$geoip2_data_country_code参数,
    # 第二个是是否允许访问,可设置为yes/no,对应于$domain_xyz_allowed_country参数
    BG no;
    }

    在网站的配置中添加路由,用于处理是否允许指定国家IP的访问

    1
    2
    3
    4
    5
    6
    7
    # 此处配置的内容位于server配置项中。
    # 修改内容所在的文件是nginx网站的配置文件。
    location / {
    if ($domain_xyz_allowed_country = no) {
    return 444; # 此处你也可以设置重定向rewrite
    }
    }
  • 若希望指定国家的IP访问时,能够跳转到其它的页面,则做以下配置

    1
    2
    3
    4
    5
    6
    # 在nginx网站的配置文件中添加路由转发
    location / {
    if ($geoip2_data_country_code = BG) {
    rewrite ^(.*)? https://test.test.bg$request_uri redirect;
    }
    }

定时更新GeoIP2数据库

  • 安装geoipupdate工具

    1
    2
    3
    4
    sudo apt install geoipupdate

    # 安装完毕后检查安装是否成功
    geoipupdate --version
  • 进入官网登录,找到个人账户密钥。进入个人中心,依次点击【Automatic Updates】–>【Generate new license key】,然后根据内容提示生成【账户信息】,最终得到的结果如下:

  • 编辑配置geoipupdate的配置文件信息,配置文件位于:/etc/GeoIP.conf,配置文件信息如下:

    1
    2
    3
    4
    5
    6
    # 配置账户信息,该账户信息是注册用户个人独有的
    AccountID 对应[Account/User ID]
    LicenseKey 对应[License Key]
    EditionIDs GeoLite2-Country GeoLite2-City
    # 配置GeoIP数据库存放的路径
    DatabaseDirectory /var/GeoIP2
  • 配置完成后,执行geoipupdate,看是否报错,若无报错即可

    1
    geoipupdate
  • 利用cron定时执行geoipupdate命令以更新数据库信息,cron定时任务的配置文件是:/etc/crontab

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 编辑配置文件
    sudo vim /etc/crontab

    # 在配置文件的末尾处添加以下内容:
    59 13 * * 5 root /usr/bin/geoipupdate

    # 添加完毕后,重新启动cron服务
    sudo service cron restart

    # 关于配置定时任务,也可以通过命令,然后回进入页面让添加新的任务
    crontab -e

    image-20200913214924869

知识点

  1. 文章主要参考如下链接,感谢博主的细心总结:

    https://www.azio.me/how-to-install-ngx_http_geoip2_module/

    https://dokov.bg/nginx-geoip2/

    https://www.cnblogs.com/baxiqiuxing/p/12376879.html

  2. 个人借鉴

    配置前前后后花费数日,期间多次失败,参考无数配置教程,却一直迷失于GeoIP和GeoIP2的版本中,而后又因为nginx的静态安装和动态安装的问题,头疼不已。所幸后来推倒重来,借助于上述链接,静下心来思考和尝试,才最终成功,可见急躁可以有,但是耐心和细心不可无。配置完毕再回头,偶遇一篇博文,说到了用docker虚拟环境去测试搭建,而我却一直用真实环境在弄,不免显得有些傻逼了。

  3. 计划

    • 找找nginx的配置教程和内容
    • 找找docker的教程
    • 寻找cron定时任务的教程