Deploy Nominatim

OpenStreetMap geocoder turning addresses into coordinates and back

Deploy Nominatim

Just deployed

/var/lib/postgresql/16/main

Deploy and Host Nominatim on Railway

Nominatim is the geocoder behind search on openstreetmap.org. It turns a written address into coordinates and a pair of coordinates back into an address, using nothing but OpenStreetMap data and a PostgreSQL database you control. Mapping teams, logistics platforms and anyone tired of per-request billing from Google or Mapbox self-host Nominatim for unmetered geocoding with no API quota and no user addresses leaving their infrastructure.

Deploy Nominatim on Railway as a single nominatim service. It packages the Nominatim 5.3 API, the OSM importer and a PostgreSQL 16 database with PostGIS in one container, with the cluster on a Railway volume at /var/lib/postgresql/16/main. A Caddy front door serves nominatim-ui at /ui/, proxies every API route, and protects both with HTTP basic auth, because Nominatim ships no authentication of its own. The first deployment imports the extract named by PBF_URL; every later one finds the finished database on the volume and serves in seconds.

Diagram of the single Nominatim service and its database volume on Railway

Getting Started with Nominatim on Railway

The template defaults to the Monaco extract, so the first import finishes in under a minute — change PBF_URL before deploying if you want another region. The logs show the download, osm2pgsql loading it, the index ranks building, then Starting Gunicorn. Open the deployed URL: the browser asks for API_USERNAME and API_PASSWORD, then redirects to /ui/, the nominatim-ui search page. Type a place name that exists in your extract and press Search — a result card and a map marker confirm the import worked.

Click details on any result for the full OpenStreetMap record: every localised name, the address breakdown, the search and address ranks, and the computed postcode. The Reverse tab turns a coordinate pair into the nearest addressable feature. The same answers come back as JSON from /search?q=...&format=jsonv2 and /reverse?lat=...&lon=...&format=jsonv2, which is what your application calls. /status is left unauthenticated for health checks and monitoring; it queries the database and reports the software version and the age of your data.

Nominatim search for Casino de Monte-Carlo with the match on a map

Nominatim place details listing every name, tag and rank

Reverse geocoding a coordinate pair to Place du Casino

About Hosting Nominatim

Nominatim is a search engine built for OpenStreetMap's data model. Importing an extract is not a copy: osm2pgsql loads the raw OSM objects, then Nominatim derives a place hierarchy — country, state, county, city, suburb, street, house number — computes address interpolations, normalises names through an ICU tokenizer, and builds the indexes that let a free-text query resolve to one building.

Key capabilities:

  • Forward geocoding, structured address search, and reverse geocoding from coordinates
  • Polygons, bounding boxes, address breakdowns and per-language name variants
  • Continuous replication of OpenStreetMap's own diffs, so your data stays current
  • JSON, GeoJSON, GeoCodeJSON and XML output, compatible with existing Nominatim clients

The service holds three cooperating parts. PostgreSQL 16 with PostGIS stores the place table and its indexes on the volume. The Nominatim API runs under Gunicorn with uvicorn workers sized from the container's CPU quota. Caddy sits in front, serving nominatim-ui, proxying the API, and applying basic auth so the deployment is not an open geocoder for strangers. One caveat worth knowing: the optional Wikipedia and Wikidata importance tables are not imported, so forward search may prefer a less prominent match among identically named places. Reverse geocoding is unaffected.

Why Deploy Nominatim on Railway

Railway removes the parts of self-hosting Nominatim that go wrong:

  • One click provisions the container, the volume and the public domain
  • The import runs on first boot and is skipped on every deploy afterwards
  • PostgreSQL memory and worker counts are derived from your plan's limits
  • The health check waits out a long first import instead of failing the deploy
  • Basic auth and TLS are in place before the service is reachable

Common Use Cases

  • Address autocomplete and validation in a checkout or onboarding form, with no per-lookup fees
  • Reverse geocoding fleet, delivery or asset telemetry into street addresses
  • Batch-geocoding a customer database privacy rules forbid sending to a third party
  • Backing an internal mapping tool where usage spikes make a metered geocoder unpredictable

Dependencies for Nominatim

  • mediagis/nominatim:5.3 — the project's own container: Nominatim 5.3.2, PostgreSQL 16, PostGIS, osm2pgsql
  • nominatim-ui 3.12.0 — the official web frontend, served from /ui/
  • caddy:2 — the front door providing basic auth and static file serving
  • A Railway volume — where the PostgreSQL cluster and the imported data live

Environment Variables Reference

VariablePurpose
PBF_URLThe OpenStreetMap extract to import on first boot
API_USERNAME / API_PASSWORDHTTP basic auth credentials for the UI and API
API_AUTHSet to disabled to serve anonymously
NOMINATIM_PASSWORDPassword for the internal PostgreSQL role
REPLICATION_URLThe -updates/ directory beside your extract
UPDATE_MODEcontinuous, once, catch-up, or unset to freeze the data
THREADS / GUNICORN_WORKERSImport threads and API workers; default to the CPU quota
REVERSE_ONLYSkip the search index for a smaller, reverse-only database
IMPORT_STYLEfull, street, address or admin — detail versus import speed

Deployment Dependencies

Hardware Requirements for Self-Hosting Nominatim

Requirements scale with the extract, not with traffic. The table covers a city or small-country extract.

ResourceMinimumRecommended
CPU2 vCPU4–8 vCPU (import is parallel)
RAM2 GB8 GB
Storage5 GB volume~10× the .osm.pbf size
RuntimePostgreSQL 16 + PostGIS, Python 3same

A country extract of a few hundred megabytes imports in tens of minutes and wants a volume in the tens of gigabytes. A whole-planet import needs roughly 1 TB of fast SSD.

Self-Hosting Nominatim

To change region, point PBF_URL at any Geofabrik extract and redeploy onto an empty volume. For Great Britain:

PBF_URL=https://download.geofabrik.de/europe/great-britain-latest.osm.pbf
REPLICATION_URL=https://download.geofabrik.de/europe/great-britain-updates/
UPDATE_MODE=continuous

Query it from any HTTP client. The following uses curl with the basic-auth credentials:

curl -u "$API_USERNAME:$API_PASSWORD" \
  "https://your-app.up.railway.app/search?q=10+Downing+Street&format=jsonv2&limit=1"

curl -u "$API_USERNAME:$API_PASSWORD" \
  "https://your-app.up.railway.app/reverse?lat=51.5034&lon=-0.1276&format=jsonv2"

How Much Does Nominatim Cost to Self-Host?

Nominatim is free and open source under GPL-2.0, and OpenStreetMap data is free under the ODbL. There is no paid tier, no seat count and no request quota — the only cost is the infrastructure, billed by Railway for the container's CPU, memory and volume. That is the appeal next to Google Geocoding, Mapbox or LocationIQ, which charge per request once a modest free allowance is gone. Attribution to OpenStreetMap contributors is required when you display results.

FAQ

What is Nominatim? Nominatim is the open-source geocoding engine behind OpenStreetMap's search box. It converts addresses and place names into coordinates, and coordinates back into addresses, from an OpenStreetMap extract loaded into PostgreSQL.

What does this Railway template deploy? One service running Nominatim 5.3, PostgreSQL 16 with PostGIS and the nominatim-ui frontend, with a volume for the database and a Caddy front door adding HTTP basic auth. It imports the extract named by PBF_URL on first boot.

Why does Nominatim need a volume instead of a managed database? Nominatim's importer initialises its own PostgreSQL cluster, installs PostGIS and a large body of PL/pgSQL, and tunes the server for a bulk load. Railway's managed Postgres has neither PostGIS nor those settings, so the database runs inside the service and persists on the volume.

How do I geocode a different country or region? Point PBF_URL at another Geofabrik extract, set REPLICATION_URL to the matching -updates/ directory, and deploy onto a fresh volume — the import only runs when the volume holds no database.

How do I keep the OpenStreetMap data up to date? Leave UPDATE_MODE=continuous and REPLICATION_URL set. A background process applies OpenStreetMap's published diffs on the REPLICATION_UPDATE_INTERVAL schedule, and /status reports the newest data applied.

Can I expose the API without a password? Yes — set API_AUTH=disabled and redeploy. Do that only if you mean to run a public geocoder, since an open endpoint is usable by anyone who finds the URL.


Template Content

More templates in this category

View Template
Rocky Linux
Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀

codestorm
47
View Template
Foundry Virtual Tabletop
A Self-Hosted & Modern Roleplaying Platform

Lucas
71
View Template
Letta Code Remote
Run a Letta Code agent 24/7. No inbound ports, just deploy.

Letta
51