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
./configureでMakefileを生成する。
先程の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