はじめに
Nginxのアクセスログには、送信元のIPアドレスが表示されると思います。その情報を使ってどの国からアクセスしているのかを確かめる方法があることを知ったので、今回その方法について書き残しておこうと思います。
想定読者
- nginxに興味がある方
実行環境
EC2インスタンスにて実施
OS:AL2023
Nginxのバージョン:nginx/1.24.0
地理情報を追加したログ
アクセス元の国や地域の情報を見れるようにしたNginxのアクセスログは下記のような形となります。

画像が見づらくて申し訳ないのですが、AWS上に立てたサーバに様々な国からアクセスされていることが分かります。
アクセスログにアクセス元の地理情報を含める方法
Nginxのアクセスログにアクセス元の地理情報を含める際に私が行ったことは下記の4点になります。
- libmaxminddbをインストールする。
- ngx_http_geoip2_moduleをNginxに組み込む
- GeoLite2をダウンロードする
- nginxの設定ファイルを編集する
各用語の役割
libmaxminddbやngx_http_geoip2_moduleなど初めて聞くような用語が並んでおりますが、各用語のざっくりとした説明は下記の通りです。
-
libmaxminddb
地理情報が格納されたデータベースにアクセスするためのライブラリ(コードの集まり)のこと。 -
ngx_http_geoip2_module
Nginxが地理情報を取得するためのモジュールのこと。モジュールを利用して特定の機能を追加することができる。 -
GeoLite2
地理情報が格納されたデータベースのこと。
libmaxminddbをインストールする。
libmaxminddbをインストールする方法として、 githubからソースコードをダウンロードして、ビルドする方法があります。
libmaxminddbはソースコードが下記のgithub上で公開されています。
https://github.com/maxmind/libmaxminddb?tab=readme-ov-file
具体的な方法は上記サイトに沿って行います。私は、「From a GitHub "Source Code" Archive / Git Repo Clone」の手順を行いました。
# gitのコマンドを利用するためgitをインストールする
sudo dnf install git
# 上記サイトに「You will need automake, autoconf, and libtool installed in addition to make and a compiler.」という記述があるので各種インストールする。
sudo dnf install automake autoconf libtool make
# gitのリポジトリをローカルにコピーする
git clone --recursive https://github.com/maxmind/libmaxminddb.git
# リポジトリに移動する
cd libmaxminddb/
# ビルドを行うための準備を行う
./bootstrap
# 上記サイトの「To install this code, run the following commands:」の指示に従い各種コマンドを実行する
./configure
make
make check # こちらのコマンドを実行したところ、「3 of 20 tests failed」という表示が出ましたが、私はそのまま下記コマンドを続けて実行しました。
sudo make install
sudo ldconfig
以上でlibmaxminddbのインストールは終了です。なおパッケージ管理ツールでもlibmaxminddbをインストールできるらしいです。
ngx_http_geoip2_moduleをNginxに組み込む
続いて、Nginxが地理情報を取得するためのモジュールのソースコードをダウンロードする必要があります。こちらもgithub上で公開されておりますのでgit cloneでコピーします。
このモジュールをNginxに組み込むためには、Nginxをソースコードの状態からインストールする際にモジュールを組み込む方法と既にインストールしているnginxに後からモジュールを組み込む方法があります。ブログでは前者を中心に紹介しておりますが、ブログの後半でインストール済みのnginxに追加する方法についても紹介します。
Nginxのソースコードはこちらのサイトで公開されています。私はNginxのver1.24.0のtarファイルをダウンロードしました。理由としては、AL2023においてdnfでNginxをインストールした際のnginxのバージョンが1.24.0であったためです。
以下にその手順を記載します。
# nginxをビルドする前の準備
sudo dnf install pcre-devel zlib-devel ※これをしておくと後述の./configureでエラーが出ません。
sudo useradd -s /sbin/nologin nginx ※予めnginxユーザを作成。
# nginxのソースコードをダウンロードする
wget https://nginx.org/download/nginx-VERSION.tar.gz
# 解凍する
tar zxvf nginx-VERSION.tar.gz
# 移動する
cd nginx-VERSION
# ビルドを行う
./configure --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --user=nginx --group=nginx --modules-path=/usr/share/nginx/modules --add-dynamic-module=/(git cloneした際のディレクトリ)/ngx_http_geoip2_module
# 各オプションの説明
--sbin-path=/usr/sbin/nginx:実行可能ファイルが置かれる場所
--conf-path=/etc/nginx/nginx.conf:設定ファイルが置かれる場所※このオプションを指定したのですが、なぜか/usr/local/nginxのディレクトリの中にありました。謎です。
--pid-path=/var/run/nginx.pid:pidファイルの置かれる場所
--error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log:ログの置かれる場所
--user=nginx --group=nginx:Nginxが実行されるユーザーおよびグループを設定
--modules-path=:モジュールの置かれる場所を指定
--add-dynamic-module=:モジュールを動的モジュールとしてビルド
make
sudo make install
ソースコードからビルドした場合ユニットファイルは作成されないため、その状態でNginxを起動しようとしても「Unit nginx.service not found.」とエラーが出ます。そのため、私は新たにvim /etc/systemd/system/nginx.serviceを行い、ユニットファイルを作成しました。(研修で行ったTomcat構築に似ています。)ユニットファイルは別のサーバでRPMでインストールしたNginxのユニットファイルをそのままコピーして貼り付けた感じです。
GeoLite2をダウンロードする
データベースをダウンロードするには、こちらのサイトにサインインする必要があります。
具体的なサインイン方法は下記のサイトを参考にしてください。
私は、データベースをダウンロードするにはサインインが必要であることから、直接wgetでサーバにダウンロードせずに、一旦ローカルにダウンロードしたのち、scpを使ってサーバに移動させました。
また私がダウンロードしたのは、GeoLite2-Cityになります。
nginxの設定ファイルを編集する
最後にnginxの設定ファイルを下記のように編集します。
# load_moduleディレクティブの追加
load_module /usr/share/nginx/modules/ngx_stream_module.so;
※こちらはeventsブロックよりも上の位置に記述します
# log_formatにgeoip2の変数を追加
例) log_format main '$remote_addr - $remote_user [$time_local] - $geoip2_data_country - $geoip2_data_city [$time_local] "$request"
※デフォルトだと「log_format」と「access_log」がコメントアウトされているので、はずしたのち、上記のように修正します。
# データベースのパスを指定(httpブロックの中)
例)geoip2 /path/to/GeoLite2-City/GeoLite2-City.mmdb {
$geoip2_data_city city names en;
$geoip2_data_country country names en;
}
※新たにgeoip2ブロックを追加します。ダウンロードしたデータベースのパスを指定します。変数の末尾にある「en」は英語で表示するという意味です。日本語で表記する方法も試したのですが、うまくいきませんでした。
以上の設定により、デフォルトのログ(/var/log/nginx/access.log)に地理情報を載せることができます。
地理情報を利用したアクセス制限
送信元IPアドレスから地理情報を調べる機能を利用して、アクセス制限をすることが可能です。例えば、日本からのみアクセスを許可して、その他の国からのアクセスは拒否するには下記のように設定します。
# geoip2ブロックに下記情報を追加
$geoip2_data_country_code default=US source=$remote_addr country iso_code;
#httpブロックの中に下記情報を追加
map $geoip2_data_country_code $allowed_country {
default no;
JP yes;
}
#serverブロックの中に下記情報を追加
if ($allowed_country = no) {
return 403;
}
$geoip2_data_country_codeと$allowed_countryの2つの変数がありますが、前者はデータベースの中にある送信元IPアドレスに対応する国のコード(country iso_code 例:US)が入ります。後者は、自身が設定した変数で任意の値を格納できます。ここでは、「no」と「yes」を設定しています。
もし送信元IPアドレスに対応する国のコードがJPつまり日本であれば、yesが$allowed_countryに格納されて、それ以外であればnoが格納されます。
もし$allowed_countryがnoの場合はステータスコード403がクライアントに返されます。
以下はアクセス制限設定後のアクセスログの画像です。

最後に
IPアドレスを基にどこの国からアクセスされているがわかることで、セキュリティの対策につなげることができると感じました。今回紹介しておりませんが、データベースを定期的に更新するための機能もあるらしいので時間があれば試したいと思います。
rpmでインストールしたNginxに後からモジュールを追加できるか試したところ
rpmでインストールしたNginxに後からモジュールを追加できました。ポイントとしては、下記の2点になります。
-
rpmのNginxのバージョンと同じバージョンのNginxのソースコードをダウンロードすること
こちらはnginx -vを行いバージョンを確認した後、同じバージョンのソースコードをダウンロードします。
ソースコード自体は、既にインストール済みであったとしても必要になるとのことです。
始めからソースコードを使ってインストールする方法と違う点としては、./configureの後にmakeではなく、make modulesを使うことです。sudo make installは必要ないです。 -
./configureの際にオプションで
--with-compatを追加する。
これにより、同じOS環境であれば、別のサーバでビルドされたモジュールでも組み込むことができるらしいです。
参考サイトにあるサイトで「signature」について触れているサイトがあり、rpmでインストールしたnginxとモジュールのsignatureが一致していればそのモジュールは動かせるとのことです。以下のコマンドを実行する事でsignatureを調べることができます。
strings /usr/sbin/nginx | grep '^.,.,.,'
strings /path/to/module.so | grep '^.,.,.,'
参考サイト