Adding geoip2 to NGINX

Published on Sunday, 31 January, 2021

The following guide will help with setting up GeoIP2 database and logging locations of source IP addresses in NGINX access log. The guide is for debian, but should be simple to adopt for other distributions.

To start, we need some packages, the packages are available in bullseye repo:

# apt update
# apt install libnginx-mod-http-geoip2

We also need the GeoIP database. You can download one for free at maxmind website. You need to create an account and create API key. The files can be downloaded from their webpage, but if you have the API key you can use the following links:

https://dev.maxmind.com/geoip/geoip2/geolite2/GeoLite2-Country&license_key=GEOIP2_API_KEY&suffix=tar.gz
https://dev.maxmind.com/geoip/geoip2/geolite2/GeoLite2-City&license_key=GEOIP2_API_KEY&suffix=tar.gz

Once you have those extract them and place the .mmdb files into /etc/nginx/geoip folder:

# ls /etc/nginx/geoip/
GeoLite2-City.mmdb  GeoLite2-Country.mmdb

With the database and packages sorted, we can configure NGINX. Create a new config /etc/nginx/conf.d/geoip2.conf:

##
# Add GEO IP support 
##

geoip2 /etc/nginx/geoip/GeoLite2-Country.mmdb {
  auto_reload 5m;
  $geoip2_metadata_country_build metadata build_epoch;
  $geoip2_data_country_code source=$remote_addr country iso_code;
  $geoip2_data_country_name country names en;
}

geoip2 /etc/nginx/geoip/GeoLite2-City.mmdb {
  $geoip2_data_city_name city names en;
}

# Enabling request time and GEO codes
log_format custom '$remote_addr - $remote_user [$time_local]'
                  ' "$request" $status $body_bytes_sent'
                  ' "$http_referer" "$http_user_agent"'
                  ' "$request_time" "$upstream_connect_time"'
                  ' "$geoip2_data_country_code" "$geoip2_data_country_name"'
                  ' "$geoip2_data_city_name"';

access_log /var/log/nginx/access.log custom;

Test the config with nginx -t and restart NGINX:

# systemctl restart nginx

After which the access log will contain lines with country codes:

# cat /var/log/nginx/access.log
198.20.99.130 - - [31/Jan/2021:11:58:00 +0100] "GET /robots.txt HTTP/1.1" 200 26 "-" "-" "0.000" "-" "NL" "Netherlands" "-"

Depending on your existing config you might end up with double logs of each request, the standard NGINX log, and the custom log with GeoIP. In that case edit /ext/nginx/nginx.conf and remove (comment) the access_log line.