nginx-geoip2 creates variables with values from the MaxMind GeoIP2 databases based on the client IP (default) or from a specific variable (supports both IPv4 and IPv6).
The module supports both nginx HTTP and stream contexts.
Note
See also: whoip โ a self-hosted service for exposing IP information using MaxMind, GeoIP2 & Nginx that returns JSON/Plain data by IP. It demonstrates a complete real-world setup of this module.
First install libmaxminddb as described in its README.md.
wget http://nginx.org/download/nginx-VERSION.tar.gz
tar zxvf nginx-VERSION.tar.gz
cd nginx-VERSION
./configure --with-compat --add-dynamic-module=/path/to/nginx-geoip2
make modules
This produces objs/ngx_http_geoip2_module.so. Copy it to your nginx module path, then add to nginx.conf:
load_module modules/ngx_http_geoip2_module.so;
./configure --add-module=/path/to/nginx-geoip2
make
make install
./configure --add-dynamic-module=/path/to/nginx-geoip2 --with-stream
# or static:
./configure --add-module=/path/to/nginx-geoip2 --with-stream
The free GeoLite2 databases are available from MaxMind's website (requires signing up).
http {
...
geoip2 /etc/maxmind-country.mmdb {
auto_reload 5m;
$geoip2_metadata_country_build metadata build_epoch;
$geoip2_data_country_code default=US source=$variable_with_ip country iso_code;
$geoip2_data_country_name country names en;
}
geoip2 /etc/maxmind-city.mmdb {
$geoip2_data_city_name default=London city names en;
}
...
fastcgi_param COUNTRY_CODE $geoip2_data_country_code;
fastcgi_param COUNTRY_NAME $geoip2_data_country_name;
fastcgi_param CITY_NAME $geoip2_data_city_name;
...
}
stream {
...
geoip2 /etc/maxmind-country.mmdb {
$geoip2_data_country_code default=US source=$remote_addr country iso_code;
}
...
}Retrieve metadata about the GeoIP database.
$variable_name metadata <field>
Available fields:
build_epochโ build timestamp of the MaxMind database.last_checkโ last time the database was checked for changes (requiresauto_reload).last_changeโ last time the database was reloaded (requiresauto_reload).
Nginx will check the modification time of the database at the specified interval and reload it if the file has changed.
auto_reload <interval>
Important โ safe database update procedure: The database is
mmap()'d into the nginx worker process. Never overwrite the file in place (e.g. withcp). Always write to a temporary file first, then atomically rename it:cp GeoIP2-City.mmdb.new /data/geoip/GeoIP2-City.mmdb.tmp mv /data/geoip/GeoIP2-City.mmdb.tmp /data/geoip/GeoIP2-City.mmdbUsing
mvchanges only the directory entry (inode pointer). The worker keeps its open file descriptor to the old inode untilauto_reloadcloses it โ the oldmmapremains valid throughout. Overwriting the inode contents while it is memory-mapped causes SIGBUS (signal 7) and a worker crash.
$variable_name [default=<value>] [source=$variable_with_ip] path ...
- If
defaultis not specified, the variable will be empty when not found. - If
sourceis not specified,$remote_addris used for the lookup.
To find the data path you want, use mmdblookup:
$ mmdblookup --file /usr/share/GeoIP/GeoIP2-Country.mmdb --ip 8.8.8.8
{
"country":
{
"geoname_id":
6252001 <uint32>
"iso_code":
"US" <utf8_string>
"names":
{
"de":
"USA" <utf8_string>
"en":
"United States" <utf8_string>
}
}
}
$ mmdblookup --file /usr/share/GeoIP/GeoIP2-Country.mmdb --ip 8.8.8.8 country names en
"United States" <utf8_string>
This translates to:
$country_name default="United States" source=$remote_addr country names en;string_uriencode on;When enabled, UTF-8 string values from the GeoIP database are percent-encoded before being placed into nginx variables. This prevents issues with non-ASCII characters (for example, Japanese city names like ลbu) being passed as raw UTF-8 bytes in HTTP headers, which can cause failures in strict upstream frameworks or libraries.
MaxMind began introducing more non-ASCII content in 2023 (see MaxMind release notes).
These work the same as the original ngx_http_geoip_module. Note: if source=$variable is provided on a variable, these settings are ignored for that variable.
geoip2_proxy <cidr>;Defines trusted addresses. When a request comes from a trusted address, the IP from the X-Forwarded-For header is used instead.
geoip2_proxy_recursive on | off;When off, the last address in X-Forwarded-For is used. When on, the last non-trusted address in X-Forwarded-For is used.
See test/README.md for instructions on building and running a Docker container to test the module locally.