Skip to content

WSL2で動いているNginx1.28.0でGeoIP2を使う

はじめに

Nginxのアクセスログを眺めるのは楽しい。だが、Nginxの標準設定のまま、単一のaccess.logにまとめてログを出力すると、

  • スキャナーBotによる脆弱性のスキャン
  • 明らかなアタックを444で切断したもの
  • 各種検索エンジンのクローラー
  • スクレイピングと思われる連続アクセス

などのリクエストのログが、全て同じログファイルに混ざり合ってしまい、かなり視認性が落ちるのでゆっくりできない。

別の記事に改めて書くつもりだが、nginx.confに色々判定を入れて、それぞれダブりがないように5つのログファイルに分割した。条件によって順番にフィルターをかけていき、全てのフィルターを通過した後、access.logには(ほぼ)人間のログのみが残る、という寸法である。

実際に運用しながらnginx.confの設定を育てていったのだが、スクレイピングに見えるログがaccess_logにそれなりに残ってしまった。無論、おれが一番知りたいのは、「おれの書いたものについて、生の人間がどのくらい読んでくれているのか?」である。

最初はIPひろばなどのサービスを使って、IPアドレスをシコシコとwhoisで逆引きしていたのだが、途中で馬鹿馬鹿しくなった。こんな作業は人間がやることではない。システムに自動でやらせるべきことだ。馬鹿かおれは。

なんか良い方法ない?とAIに尋ねると、MaxMind社が提供しているGeoIP2を使うことで、無料版でもそれなりの情報が取れるということが分かった。"Nginx GeoIP2"で検索しても日本語の説明サイトはほぼ無かったので、ChatGPTに訊きながら作成した手順をメモしておく。

soをビルドする

sudo aptで簡単に入るかなあ、と思っていたのだが、エラーが出て即死した。soファイルのビルドから必要らしい。

ビルドが必要となると一気にハードルが高くなったが、コマンドはChatGPTが教えてくれるので、やってみよう。

ビルド準備

まず、ビルドに必要な資材をダウンロードしていく。

必要モジュールをインストール

必要なモジュールをapt installする。対象はChatGPTに言われたまま。

$ sudo apt update
$ sudo apt install -y \
    build-essential \
    git \
    wget \
    libmaxminddb-dev \
    libpcre2-dev \
    zlib1g-dev \
    libssl-dev

作業フォルダを作成

ビルド用の作業ディレクトリを/tmp配下に作成して移動する。

$ cd /tmp
$ mkdir nginx-geoip2-build
$ cd nginx-geoip2-build

Nginxソースを取得

Nginxのソースファイルをwgetでダウンロードし、nginx-1.28.0.tar.gzを展開する。(今は「解凍」とは言わないんだね)

$ wget https://nginx.org/download/nginx-1.28.0.tar.gz
$ tar xf nginx-1.28.0.tar.gz

GeoIP2をclone

続いて、Githubから本命のGeoIP2のプロジェクトをcloneする。

$ git clone https://github.com/leev/ngx_http_geoip2_module.git

現在の状態

これでビルドの準備が整った。

$ ll
(中略)
drwxr-xr-x  9 dezikomoe dezikomoe    4096 Jul 13 22:14 nginx-1.28.0/
-rw-r--r--  1 dezikomoe dezikomoe 1280111 Apr 23  2025 nginx-1.28.0.tar.gz
drwxr-xr-x  3 dezikomoe dezikomoe    4096 Jul 13 22:10 ngx_http_geoip2_module/

ビルド実行

Nginxの情報取得

ビルド実行にあたり、nginx -VでNginxの詳細な情報を取得する。必要になるのはconfigure arguments:の後ろのパラメーターだ。

$ nginx -V
nginx version: nginx/1.28.0
built by gcc 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)
built with OpenSSL 1.1.1f  31 Mar 2020
TLS SNI support enabled
configure arguments: ●●●●

./configure

./configureMakefileを生成する。

先程のnginx -Vで出力されたconfigure arguments:の末尾に、--add-dynamic-module=../ngx_http_geoip2_moduleを足すだけでOK。

$ cd /tmp/nginx-geoip2-build/nginx-1.28.0
$ ./configure ●●●● --add-dynamic-module=../ngx_http_geoip2_module

Makefileを確認

問題なければMakefileが無事に生成されているはず。どうなったか見てみよう。(トランプ風)

$ ll Makefile
-rw-r--r-- 1 dezikomoe dezikomoe 375 Jul 13 22:14 Makefile

make

Makefileが生成できたので、make modulesでビルドする。

$ make modules

モジュールを確認

objs/の下を確認すると、無事に目的のsoファイルがビルドできていた。

$ ll objs/*.so
-rwxr-xr-x 1 dezikomoe dezikomoe 119160 Jul 13 22:14 objs/ngx_http_geoip2_module.so*
-rwxr-xr-x 1 dezikomoe dezikomoe  93088 Jul 13 22:14 objs/ngx_stream_geoip2_module.so*

Nginxへ配置

生成したsoファイルを/usr/lib/nginx/にコピーしておく。

$ sudo cp objs/ngx_http_geoip2_module.so /usr/lib/nginx/modules/
$ sudo cp objs/ngx_stream_geoip2_module.so /usr/lib/nginx/modules/
$ ll /usr/lib/nginx/modules/*.so
-rwxr-xr-x 1 root root 119160 Jul 13 22:16 /usr/lib/nginx/modules/ngx_http_geoip2_module.so*
-rwxr-xr-x 1 root root  93088 Jul 13 22:16 /usr/lib/nginx/modules/ngx_stream_geoip2_module.so*

作業ディレクトリ削除

これでもう作業用のディレクトリは削除してOK。

$ rm -rf /tmp/nginx-geoip2-build/

mmdbを取得する

MaxMindの公式サイトから、データベースのmmdbファイルを取得する。まずはMaxMindアカウント作成からだ。

MaxMindのアカウントを作成する

GeoLite sign upからサインアップしてアカウントを作成する。メールアドレスがあればOK。

サインアップするとサインアップ時のメールが飛んでくるのでパスワードを生成し、そのパスワードを使ってログインする方式である。ログインすると、今度はメールアドレスに対して6桁の認証コードが飛んでくるので、それを入力すればいい。

mmdbをダウンロードする

MaxMindにアクセスし、左側のメニュー「GeoIP / GeoLite」から、「Download files」を選ぶ。

「GeoLite ASN」と「GeoLite Country」のmmdbをダウンロードする。

今回は「GeoLite City」は使わない事にした。スクレイピングBotを判定したいだけなので、不必要な個人情報は欲しくない。

mmdbを配置する

tar.gzから取り出したmmdbを好きな場所に置く。

今回はデフォルトの/usr/share/GeoIP/の下に置いた。ディレクトリは既に作成されていた。

$ /usr/share/GeoIP/
$ ll *mmdb
-rw-r--r-- 1 dezikomoe dezikomoe 12100745 Jul 14 17:15 GeoLite2-ASN.mmdb
-rw-r--r-- 1 dezikomoe dezikomoe  8844154 Jul 10 16:13 GeoLite2-Country.mmdb

nginx.conf更新

ビルドしたsoファイルと、ダウンロードしたmmdbを、nginx.confの設定に組み込む。

load_moduleを指定

eventsの前にload_moduleディレクティブを書く。

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /run/nginx.pid;

# ビルドしたGeoIP2
load_module modules/ngx_http_geoip2_module.so;

events {
    worker_connections  1024;
}
(後略)

geoip2を指定

httpブロックにgeoip2ディレクティブを書く。

http {
  (中略)
    # GeoIP2の設定
    geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
        auto_reload 1h;
        $geoip_country_code country iso_code;
        $geoip_country_name country names en;
    }
    geoip2 /usr/share/GeoIP/GeoLite2-ASN.mmdb {
        auto_reload 1h;
        $geoip_asn autonomous_system_number;
        $geoip_org autonomous_system_organization;
    }

起動前チェック

お約束の構文チェックを念のため実行してNginxを再起動すればOK。

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl reload nginx

ログを出力する

以下の値を使うことで、$remote_addrのIPアドレスを元に、mmdbから情報を引き当てすることができる。

実際に取得した値をサンプルとして例示する。

  • $geoip_country_code:国コード:US
  • $geoip_asn:ASNコード:212238
  • $geoip_org:団体:Datacamp Limited

団体の$geoip_orgには、「KDDI CORPORATION」や「BIGLOBE Inc.」が入る。

国コードと組み合わせて見ることで、そのアクセスが人間によるものか、Botなどによるものかを容易に判断可能だと言えるだろう。

なお、ローカルIPアドレスの場合は、国コードは-になる。

mmdbの自動更新

mmdbは適宜更新が入るので、MaxMindから自動でmmdbを取得し更新する設定を入れておこう。

ChatGPTに調べてもらうと、これは/etc/GeoIP.confで設定可能なようだ。

GeoIP.conf

見てみると、既に/etc/GeoIP.confが作成されていた。

$ ll /etc/GeoIP.conf
-rw-r--r-- 1 root root 1929 Jul 10  2025 /etc/GeoIP.conf

これをviなどで編集していく。

$ sudo vi /etc/GeoIP.conf

設定内容は以下の通り。

  • AccountIDは、ログイン時のユーザIDではないので注意。MaxMindにログイン後、「My Account」で確認できる。
  • LicenseKeyは、同じく「My Account」から発行が必要である。発行する際に、丁寧にconfのダウンロードまでできる。
(前略)
AccountID MaxMindのアカウントID
LicenseKey MaxMindのライセンスキー

# Enter the edition IDs of the databases you would like to update.
# Multiple edition IDs are separated by spaces.
EditionIDs GeoLite2-Country GeoLite2-ASN
(後略)

更新実行

geoipupdateを実行して、mmdbを更新する。

$ sudo geoipupdate

なお、ライセンスキー発行後の画面に表示される通り、ライセンスキーが有効になるまで数分間のラグがある。

実際に、即座に実行してみたら認証に失敗して焦った。

$ sudo geoipupdate
Error retrieving updates: running the job processor: running job: unexpected HTTP status code: received HTTP status code: 401: {"code":"AUTHORIZATION_INVALID","error":"Your account ID or license key could not be authenticated."}

crontab用のシェルスクリプトを作る

シェルスクリプトを作ってcrontabに入れておく。

$ cd ~/dezikomoe_sh
$ touch geoipupdate.sh
$ chmod +x geoipupdatesh
$ vi geoipupdate.sh

シェルスクリプトの内容

シェルスクリプトは、単にgeoipupdateを実行してログを出力するだけ。エラーにならなければ空ファイルになる。

#!/bin/bash
geoipupdate > /home/dezikomoe/dezikomoe_sh/geoipupdate.log 2>&1

crontabを登録する

sudo crontab -eでcrontabを登録する。毎日04:00に起動するように設定した。

ChatGPTによると、実際には週1回程度でも十分とのこと。

0 4  * * *   /home/dezikomoe/dezikomoe_sh/geoipupdate.sh 

更新確認

実際に更新できたのを後日確認した。04:00にcrontabでシェルスクリプトを実行し、更新されているのが分かる。

$ ll /usr/share/GeoIP/ | grep mmdb
-rw-r--r--   1 root root 12117019 Jul 20 04:00 GeoLite2-ASN.mmdb
-rw-r--r--   1 root root  8809422 Jul 19 04:00 GeoLite2-Country.mmdb