nshgeoip — Small Local GeoIP Lookup Service
Daniel Nashed – 27 August 2026 21:04:04
While working on CrowdSec and NGINX integration, I needed a simple and efficient way to perform local GeoIP lookups.There are several ways to integrate GeoIP information directly into individual products, but I wanted something more generic: a small local service that can be shared by NGINX, CrowdSec integrations, scripts, containers, and other applications.
The result is nshgeoip.
What is nshgeoip?
nshgeoip is a small C++ service using MaxMind MMDB databases through libmaxminddb.
It provides GeoIP information such as:
- Country and continent
- ASN and organization
- City and postal code
- Latitude and longitude
The normal interface is a UNIX domain socket:
IP address -> nshgeoip -> local MMDB lookup -> GeoIP information
An optional TCP listener is available for cases where the consumer runs in another container or network namespace.
A lookup is simply:
GET /lookup?ip=8.8.8.8
and returns information as JSON as well as useful X-GeoIP-* response headers.
For example, NGINX can use nshgeoip through an auth_request subrequest to obtain GeoIP information and then decide itself how that information should be used.
Alpine static binary without any external dependencies
For the container build, nshgeoip is compiled as a fully static binary using musl on Alpine Linux, including a statically linked libmaxminddb.
Alpine is only used as the build stage. The final runtime image is built FROM scratch, so Alpine itself isn't part of the resulting image.
There is no Linux distribution, shell, package manager, or other runtime dependency — essentially just the nshgeoip binary.
The service provides GeoIP lookups, health checks, Prometheus metrics, IPv4/IPv6 support, UNIX socket and optional TCP access, and concurrent request processing.
The GeoIP databases themselves are mounted separately and can therefore be updated independently from the container image.
Fast local lookups
The MaxMind MMDB databases are opened once at startup using the normal memory-mapped access provided by libmaxminddb.
There is no need for an additional application-level cache or to reopen a database for every request.
A small fixed-size worker pool handles concurrent requests.
During load testing, nshgeoip easily handled tens of thousands of lookups per second.
That's far beyond what is required for the intended use case, where a local service such as NGINX performs a GeoIP lookup while processing a request.
Health and metrics included
Because nshgeoip is also intended to run as a small infrastructure service, health and monitoring support are built in:
/lookup
/health
/metrics
/health can be used for Docker and Kubernetes health checks.
The FROM scratch container doesn't contain curl, wget, or even a shell, so the binary also provides its own health-check command.
This allows Docker to check the service without adding another tool to the image just for health monitoring.
/metrics provides Prometheus metrics including request counters, lookup results, HTTP response codes, and the age of the loaded GeoIP databases.
Metrics can optionally also be written periodically to a Prometheus textfile collector directory.
Getting information about GeoIP databases
There are separate command line tools to check the database. But they are not included in Ubuntu and other distributions.
So I added the functionality also into the binary.
For example:
nshgeoip --check-db /var/lib/GeoIP/GeoLite2-City.mmdb
shows information including the database type, build date, and age.
The service also reports database age through its health and Prometheus interfaces, making it possible to detect outdated GeoIP data automatically.
Local GeoIP mirror for internal environments
For environments where servers should not download GeoIP databases directly from the Internet, I also added a small update and synchronization architecture.
One designated system downloads the databases from MaxMind and provides them through an internal NGINX mirror. Other systems synchronize the databases from this internal source with checksum verification.
This means only one system needs MaxMind credentials and Internet access.
It also fits well with isolated or tightly controlled server environments where application servers shouldn't make external connections just to keep GeoIP information current.
Very small footprint
With a container image below 1 MB, no runtime operating system, no outbound network dependency, and built-in health and Prometheus support, it turned into a useful little infrastructure building block.
Source code
nshgeoip is open source and available on GitHub:
nashcom/nshgeoip
https://github.com/nashcom/nshgeoip
- Comments [0]