Skip to main content
Back to projects

IP Geolocation

An address becomes a place.

A self-hosted IP geolocation and timezone API. The MaxMind GeoLite2 database and the timezone boundaries ship inside the container, so a lookup is a local read rather than a call to somebody else's service.

request pick one

response

{
  "latitude": 37.751,
  "longitude": -97.822,
  "city": "",
  "country_name": "United States",
  "time_zone": { "name": "America/Chicago" },
  "languages": "en-US,en"
}

rust ·0 third-party calls·JSON and protobuf·GeoLite2 in the image·amd64 and arm64

The API

Two shapes. The short one keeps a small, stable payload. The /v1 one adds currency, calling code, flags and the rest.

# The caller's own address, detected from proxy headers
GET /

# A specific address, short shape
GET /ipgeo?ip=8.8.8.8

# A specific address, full shape
GET /v1/ipgeo?ip=8.8.8.8

# Coordinates to timezone. Note the parameter is `long`, not `lon`.
GET /timezone?lat=51.5074&long=-0.1278

The service also publishes /openapi.yaml and /llms.txt, so it can describe itself to a code generator and to an agent without anyone hand-writing a client.

Run your own

The image carries its own data, so there is no API key to obtain and no account to create.

docker run -p 3000:3000 ghcr.io/vpetersson/ipgeolocation:latest
curl "http://localhost:3000/ipgeo?ip=8.8.8.8"

Put it behind your proxy and it reads CF-Connecting-IP, X-Real-IP and X-Forwarded-For, so GET / answers for the real caller rather than for the proxy. An in-memory LRU sits in front of the database, and responses carry Cache-Control so a proxy can hold them too.

What you get

The addresses stay with you

A hosted geolocation API sees every address you look up, which for most applications means every visitor you have. This one sees nothing, because it is yours.

No rate limit, no key

The data is in the image. A lookup costs a memory read, so there is no quota to budget and no key to rotate.

Predictable latency

Nothing in the request path crosses the internet, so a lookup does not inherit somebody else's outage or slow afternoon.

Timezones from geometry

Coordinates resolve against real timezone boundaries with tzf-rs, rather than being guessed from the country.

Protobuf when you want it

Ask for protobuf instead of JSON on the routes where payload size actually matters.

Published with an SBOM

Every release publishes a software bill of materials, so what is inside the image is a matter of record.

MIT licensed, built in Rust. Source, issues, and images at ghcr.io/vpetersson/ipgeolocation.