Skip to main content

Configuration

A Docker deployment of OpenMapX reads one environment file: infra/docker/.env. Copy it from the tracked template and fill in the handful of required values:

cp infra/docker/.env.example infra/docker/.env

Both Docker Compose and the openmapx CLI auto-load this file from the directory containing the generated compose file, so you set a value once and both sides see it. At docker compose up time, Compose substitutes the values into the ${VAR} placeholders in the rendered YAML, and the service manifests forward the resolved values into each container's environment.

A few conventions are worth knowing before the tables:

  • Required values fail loud. The most critical keys are written into the generated stack as ${VAR:?error} — Compose refuses to start if they are unset, so production can't silently ship with a placeholder. They are marked Required below.
  • .env.example is the source of truth. Nearly every key documented here exists in that file, usually with an inline comment and a default (a few provider-level INTEGRATION_* overrides are documented for completeness even when the template omits them). When in doubt, read the template.
  • Most feature credentials live in the admin UI, not here. API keys for individual integrations (tile providers, transit feeds, weather, fuel prices, and so on) are managed at /admin/integrations. Anything you do set in .env always wins over an admin-stored value. See How it works for the service/integration model.
Recreate containers after editing

Changing .env only takes effect when the affected containers are recreated. Re-run docker compose up -d (Compose detects the changed file and recreates what's needed) or restart through the CLI's service commands.

Core / required

The values without which the stack won't start. Generate the secrets — never ship the placeholders.

VariableDescriptionRequired / Default
DOMAINPublic domain. Drives Traefik routing, the auth URLs (BETTER_AUTH_URL, PASSKEY_RP_ID, PASSKEY_ORIGIN), the web app's NEXT_PUBLIC_API_URL, tile-server URLs, and the outbound contact identity (the contact address in third-party User-Agent strings and the email From fallback). Point both an A and an AAAA record at the host.Default localhost
ACME_EMAILContact email for Traefik's automatic Let's Encrypt TLS certificates.Default admin@example.com
POSTGRES_PASSWORDPassword for the PostgreSQL/PostGIS database (used by postgis, app-api, and data-manager). Compose refuses to start if unset. Generate with openssl rand -hex 32.Required
OPENMAPX_HOST_DIRAbsolute host path of the OpenMapX repo checkout. The app-api container shells out to docker compose from inside the container and bind-mounts this path at the same path on both sides, so generated bind sources like ./data resolve correctly. Find it with pwd from the repo root.Required (no default)
DOCKER_GIDThe host's docker-socket group id. Containers that mount the docker socket run as a non-root user and must join this group, or the data-manager's MOTIS import/promote fails with "permission denied". Host-specific — find it with stat -c %g /var/run/docker.sock. Compose has no fallback, so it must be set; .env.example pre-fills 999.Required
Domain and TLS networking

Traefik serves HTTP/3 (QUIC) on UDP/443 and the OpenMapX Docker network is dual-stack. For IPv6 to reach published ports, the Docker daemon needs ip6tables enabled — the default in Docker Engine 27+, otherwise add {"experimental": true, "ip6tables": true} to /etc/docker/daemon.json and restart the daemon.

Secrets

Authentication and internal service secrets. The first two are enforced at runtime by the API; DATA_MANAGER_AUTH_TOKEN is enforced at the Compose layer. Generate each with the command shown.

VariableDescriptionRequired / Default
BETTER_AUTH_SECRETBetter Auth session-signing key. No fallback — the API refuses to start without it. Generate with npx @better-auth/cli@latest secret.Required
OPENMAPX_SECRETS_KEYSymmetric key (32 bytes, hex — 64 chars) used to encrypt integration secrets stored in the vault. If unset, integrations that store secrets in the admin panel won't decrypt after a restart. Generate with openssl rand -hex 32.Required (to use the secret vault)
DATA_MANAGER_AUTH_TOKENShared secret between app-api and the data-manager service; every data-manager mutation endpoint (downloads, hardlinks, dataset reload, conversions) requires it. Compose refuses to start without it in production; development generates a random ephemeral token. Generate with openssl rand -hex 32.Required in production
OPENMAPX_LOCAL_ADMIN_TOKENShared secret for the CLI ↔ API loopback admin short-circuit. When set, loopback requests only gain admin if they carry a matching X-OpenMapX-Local-Admin header (a CSRF guard); the CLI attaches it automatically. In production with no token, the loopback bypass is denied and the CLI needs a web-login session cookie. Generate with openssl rand -hex 32.Optional (recommended). Default unset

Docker & host wiring

How the containers find the host, the repo, and bind-mounted volumes. The required pieces of this group are listed under Core / required (OPENMAPX_HOST_DIR, DOCKER_GID); the rest are optional.

VariableDescriptionRequired / Default
OPENMAPX_CUSTOM_INTEGRATIONS_DIRContainer path where community integrations (installed by the admin panel or CLI) are mounted. Leave at the default unless you also change the app-api bind-mount target.Default /app/custom_integrations
UIDHost UID for bind-mounted volumes (Linux). macOS/Windows usually don't need this — Docker Desktop handles ownership.Optional. Commented 1000
GIDHost GID for bind-mounted volumes (Linux). Same caveat as UID.Optional. Commented 1000
DATA_MANAGER_URLBase URL app-api uses to reach the data-manager. Compose overrides this to the service-network DNS name automatically.Default http://localhost:4000 (pnpm dev); compose sets http://data-manager:4000
OPENMAPX_ENABLED_SERVICESPin a specific service selection (comma- or space-separated) for CI/repeatable deploys. Wins over the service-selection.json written by the admin UI / CLI.Optional. Default: service-selection.json
OPENMAPX_DOCKER_CONFIG_DIRHost directory holding Docker registry credentials, mounted into app-api so the extension store's Update can pull private GHCR images. On the reference deploy this is /home/ubuntu/.docker.Optional. Default unset

Authentication & OAuth

Optional social-login providers. Each requires an OAuth app registered with the provider.

VariableDescriptionRequired / Default
OSM_CLIENT_IDOpenStreetMap OAuth client id. Register at the OSM OAuth applications page.Optional. Commented
OSM_CLIENT_SECRETOpenStreetMap OAuth client secret.Optional. Commented
MAPILLARY_CLIENT_IDMapillary OAuth client id (re-uses the same app as MAPILLARY_TOKEN). Register at the Mapillary developer dashboard.Optional. Commented
MAPILLARY_CLIENT_SECRETMapillary OAuth client secret.Optional. Commented

Map style & tiles

Tile-source selection and keys. The NEXT_PUBLIC_* values (except NEXT_PUBLIC_API_URL) are read per-request via the web app's EnvProvider, so runtime changes reach both server and client components without a rebuild.

VariableDescriptionRequired / Default
NEXT_PUBLIC_STYLE_PROVIDERTile source. maptiler uses MapTiler Cloud (needs a key); openmapx uses the self-hosted tile stack (needs the tiles profile).Default maptiler
MAPTILER_KEYMapTiler Cloud API key. Also settable in /admin/settings → Map. Leave commented to manage from the admin UI; uncomment to lock a value (env wins).Optional. Commented
NEXT_PUBLIC_MAP_STYLE_URLBase URL of the self-hosted tileserver-gl; the web app appends /styles/<style>/style.json. With the built-in Traefik route this is ${DOMAIN}/tiles.Optional. Commented
NEXT_PUBLIC_TILES_URLSelf-hosted tile JSON URL.Optional. Commented
NEXT_PUBLIC_TRAFFIC_TILE_URL_TEMPLATEOverride URL template for the traffic raster layer.Optional. Commented
NEXT_PUBLIC_CYCLOSM_TILE_URL_TEMPLATEOverride URL template for the CyclOSM layer.Optional. Commented
NEXT_PUBLIC_TERRAIN_TILE_URL_TEMPLATEOverride URL template for the terrain layer.Optional. Commented

Street-level imagery

Mapillary tokens for street-level imagery. One stays server-side; the viewer token ships in the browser bundle.

VariableDescriptionRequired / Default
MAPILLARY_TOKENServer-side Mapillary token used by the /api/mapillary/* vector-tile proxy and integrations that fetch Mapillary on the user's behalf. Stays server-side — street-level imagery is proxied through the API, so no Mapillary token reaches the browser.Optional. Default unset

Backend endpoint overrides

Self-hosted backends are normally resolved from the service registry. These overrides force a specific (often public) endpoint instead — useful when a backend runs outside the Compose stack. All optional and commented by default.

VariableDescriptionRequired / Default
INTEGRATION_ROUTING_OSRM_ENDPOINTOSRM endpoint for the routing provider (car routing). Usually unset — a co-deployed osrm service is auto-resolved over the internal network.Optional. Default unset
OSRM_URLOSRM endpoint used by the app-api road-snap helper (distinct from the routing provider above). Usually unset — the co-deployed osrm service is used.Optional. Default unset
VALHALLA_URLValhalla endpoint for isochrones, elevation, and road-snap (bus). The default targets Stadia Maps' hosted Valhalla, which requires VALHALLA_API_KEY; a self-hosted Valhalla needs no key. The routing/directions provider resolves separately — via the co-deployed valhalla service or INTEGRATION_ROUTING_VALHALLA_ENDPOINT / INTEGRATION_ROUTING_VALHALLA_APIKEY.Optional. Commented https://api.stadiamaps.com
VALHALLA_API_KEYAPI key for the hosted Valhalla above (free non-commercial tier at stadiamaps.com). Leave blank for a self-hosted Valhalla.Optional. Default unset
MOTIS_URLMOTIS endpoint for the transit manager and shared local MOTIS helpers. Over the internal network MOTIS listens on 8080 (8081 is only the host-loopback mapping).Optional. Commented http://motis:8080
OVERPASS_URLOverpass API endpoint used by the core Overpass client.Optional. Commented http://overpass:80
NOMINATIM_URLNominatim endpoint for station reverse-geocoding (bike / scooter / car sharing).Optional. Commented http://nominatim:8080
TRANSITOUS_URLTransitous endpoint for rental POIs used by shared-mobility integrations.Optional. Commented https://api.transitous.org

Regional defaults

Default regions and country filters used by the CLI and selected services, so you can keep them here instead of repeating CLI flags. A region passed on the command line overrides the env value for that invocation.

VariableDescriptionRequired / Default
OPENMAPX_REGIONShared default OSM region for selectors like openmapx data download osm, services build, and data convert overpass.Optional. Commented europe/germany
OSRM_REGIONPer-service OSRM build region (wins over OPENMAPX_REGION for that target).Optional. Commented
OTP_REGIONPer-service OTP build region.Optional. Commented
MOTIS_REGIONPer-service MOTIS build region.Optional. Commented planet
PELIAS_REGIONPer-service Pelias build region.Optional. Commented
TILESERVER_REGIONPer-service TileServer GL build region.Optional. Commented
OVERPASS_REGIONPer-service Overpass build region.Optional. Commented
TRANSITOUS_COUNTRIESCountry filter (e.g. de,at,ch) for data download gtfs and MOTIS Transitous config generation.Optional. Commented
INTEGRATION_GEOCODING_PROVIDERComma-separated geocoding fallback chain, tried left to right. Valid names: maptiler, photon, nominatim, pelias, motis, transitous, entur, db-ris.Optional. Default maptiler
PHOTON_REGIONRuntime download region for the self-hosted Photon index.Default planet

Service tuning

Knobs forwarded into the backend containers. Defaults are sensible for most deployments.

VariableDescriptionRequired / Default
NOMINATIM_THREADSImport/query thread count for the self-hosted Nominatim geocoder.Default 8
NOMINATIM_IMPORT_WIKIPEDIAImport Wikipedia importance scores during the Nominatim build.Default true
NOMINATIM_IMPORT_GB_POSTCODESImport GB postcodes.Default false
NOMINATIM_IMPORT_US_POSTCODESImport US postcodes.Default false
OVERPASS_SPACEOverpass database space limit, in bytes.Default 107374182400 (~100 GiB)
OVERPASS_FASTCGI_PROCESSESNumber of Overpass FastCGI worker processes.Default 4

Traffic & extra tile providers

Keys and overrides for the app-api traffic and tile proxies.

VariableDescriptionRequired / Default
TRAFFIC_PROVIDERTraffic data provider.Default tomtom
TOMTOM_TRAFFIC_KEYTomTom Flow tile-proxy key. Sign up at developer.tomtom.com.Optional. Default unset
TOMTOM_TRAFFIC_URLTomTom API base URL.Optional. Commented https://api.tomtom.com
TOMTOM_TRAFFIC_VERSIONTomTom Flow API version.Optional. Commented 4
TOMTOM_TRAFFIC_STYLETomTom Flow tile style.Optional. Commented relative-delay
TOMTOM_TRAFFIC_TILE_SIZETomTom tile size in pixels.Optional. Commented 256
TOMTOM_TRAFFIC_THICKNESSTomTom Flow line thickness.Optional. Commented 2
THUNDERFOREST_API_KEYThunderforest OpenCycleMap key (free Hobby Project key at thunderforest.com).Optional. Default unset
CYCLOSM_TILE_URLOverride URL for the CyclOSM tile proxy.Optional. Commented
WAYMARKED_CYCLING_TILE_URLOverride URL for the Waymarked Trails cycling layer.Optional. Commented
OPENTOPOMAP_TILE_URLOverride URL for the OpenTopoMap layer.Optional. Commented

Email

Used for email verification, 2FA, and email-change flows. The provider is auto-detected by priority: EmailLabs > Lettermint > SMTP. These are also settable in /admin/settings → Email / SMTP; env always wins.

VariableDescriptionRequired / Default
EMAIL_FROMSender address, e.g. OpenMapX <noreply@openmapx.example.com>.Optional. Commented
EMAILLABS_APP_KEYEmailLabs app key (emaillabs.io, 9k emails/mo free).Optional. Commented
EMAILLABS_SECRET_KEYEmailLabs secret key.Optional. Commented
EMAILLABS_SMTP_ACCOUNTEmailLabs SMTP account.Optional. Commented
LETTERMINT_API_TOKENLettermint API token (lettermint.co, 300 emails/mo free).Optional. Commented
SMTP_HOSTSMTP server hostname (any provider).Optional. Commented
SMTP_PORTSMTP port.Optional. Commented 587
SMTP_SECUREUse TLS on connect.Optional. Commented false
SMTP_USERSMTP username.Optional. Commented
SMTP_PASSSMTP password.Optional. Commented

Transitous & cron

Schedules and tuning for the daily Transitous transit-data sync.

VariableDescriptionRequired / Default
TRANSIT_SOURCEHow the Transitous dataset is obtained: mirror (default — download the prebuilt community bundle) or build (assemble it locally from feeds). See Transit engines.Optional. Default mirror
TRANSITOUS_ARTIFACT_BASE_URLBase URL the mirror mode pulls the prebuilt Transitous artifact from.Optional. Default unset (upstream)
TRANSITOUS_SYNC_CRONCron schedule for the daily Transitous sync. Leaving it unset (or empty) uses the built-in 0 3 * * *; set it to disabled (or off/false) to turn it off (e.g. on a staging host where you trigger manually).Optional. Commented 0 3 * * *
TRANSITOUS_STALENESS_CHECK_CRONCron schedule for the staleness sweep that flags feeds that have stopped updating. Set to disabled (or off/false) to turn it off.Optional. Commented 0 4 * * *
TRANSITOUS_FEED_PROXY_RELOAD_CRONCron schedule for the feed-proxy nginx-reload heartbeat — a safety net against a missed reload during sync.Optional. Commented */15 * * * *
TRANSITOUS_AUTO_BUMP_CRONOpt-in cron that advances the pinned Transitous catalog to upstream's latest behind the staging-slot canary — activates the new pin (and promotes) only if the candidate builds and passes the functional probes, otherwise keeps the current pin and alerts. Unset/empty = disabled (the pin stays frozen). See Transit engines.Optional. Default disabled
TRANSITOUS_ALERT_GH_TOKEN / TRANSITOUS_ALERT_GH_REPOWhen both are set, sync/auto-bump failures and stale feeds open deduped GitHub issues instead of being log-only. Without them a canary rejection can silently freeze the live dataset for days.Optional. Default log-only
MOTIS_RENTALS_WARMUP_MS / MOTIS_RENTALS_POLL_INTERVAL_MSHow long the rentals canary re-polls MOTIS /rentals while it enumerates zero providers (GBFS warm-up after a restart) before failing, and the interval between polls.Optional. Default 180000 / 5000
Transitous feed-proxy key

The optional age private key used to decrypt AGE-ENCRYPTED: feed values has no env variable. Drop the file at infra/docker/secrets/transitous-feed-proxy.age on the host and re-render compose; the mount is omitted automatically when the file is absent. See infra/docker/secrets/README.md for the generation steps.

Advanced & optional

Lower-level toggles, retention, and legal-page metadata. All optional.

VariableDescriptionRequired / Default
LOG_LEVELFastify log level (trace, debug, info, warn, error, fatal).Optional. Commented info
OPENMAPX_DISABLE_LOCALHOST_AUTHSet to 1 to disable the loopback admin short-circuit entirely, regardless of OPENMAPX_LOCAL_ADMIN_TOKEN. Use on multi-tenant hosts where another local process could reach the API's loopback.Optional. Commented
ISOCHRONE_PROVIDERIsochrone provider. Use otp to route isochrones through OpenTripPlanner instead of Valhalla.Optional. Commented. Default valhalla
AUDIT_LOG_RETENTION_DAYSDays to keep admin audit-log entries before the daily prune.Optional. Commented 90
ADMIN_JOB_RETENTION_DAYSDays to keep finished admin jobs (in-flight jobs are never pruned).Optional. Commented 30
GITHUB_TOKENGitHub API token — raises the Transitous catalog fetch rate limit from 60 to 5000 req/h. Needed only on multi-tenant hosts.Optional. Commented
EXTENSION_CATALOG_URLDefault catalog URL for the Extensions store — the curated (verified-tier) list shown under /admin/extensions.Optional. Commented https://raw.githubusercontent.com/openmapx/community-extensions/main/catalog.json
LEGAL_NAMEOperator legal name shown on /terms and /privacy.Optional. Commented
LEGAL_STREETOperator street address.Optional. Commented
LEGAL_POSTAL_CODEOperator postal code.Optional. Commented
LEGAL_CITYOperator city.Optional. Commented
LEGAL_COUNTRYOperator country.Optional. Commented
LEGAL_JURISDICTION_CITYCity of legal jurisdiction.Optional. Commented
LEGAL_EMAILLegal contact email.Optional. Commented
LEGAL_PHONELegal contact phone.Optional. Commented
LEGAL_SUPERVISORY_AUTHORITYData-protection supervisory authority (name + address) named on /privacy. Leave blank to omit the sentence.Optional. Commented
LEGAL_SUPERVISORY_AUTHORITY_URLURL of the supervisory authority above.Optional. Commented
LEGAL_HOSTING_PROVIDERHosting provider (name + address) disclosed on /privacy. Leave blank to omit.Optional. Commented
LEGAL_HOSTING_LOCATIONSHuman-readable hosting locations shown on /privacy, e.g. Germany and Finland (EU).Optional. Commented
LEGAL_SERVER_LOG_RETENTION_DAYSDays server logs are retained, stated on /privacy. Must be a whole number; a non-numeric value is ignored.Optional. Default 30
Legal pages

The legal fields are optional but required for complete production /terms and /privacy pages. Leave them blank to omit the corresponding rows.

Data-use policy

Each data source declares whether it may be used commercially. By default the stack serves everything — the reference deployment is non-commercial — but a commercial operator can exclude licence-restricted sources. These are resolved env-first, then the admin toggle at /admin/settings, then the default, and have no entry in .env.example; set them only if you need to restrict. See Data-use policy for what each class covers.

VariableDescriptionRequired / Default
OPENMAPX_ALLOW_NONCOMMERCIALSet to false/0 to exclude sources whose licence forbids commercial use (commercialUse: "no"). Overrides the admin toggle.Optional. Default true
OPENMAPX_ALLOW_GREY_AREASet to false/0 to exclude sources with unclear or undocumented terms (commercialUse: "unknown"). Overrides the admin toggle.Optional. Default true

Overture Maps POIs

Schedules and switches for the monthly Overture Maps POI data ingestion.

VariableDescriptionRequired / Default
OVERTURE_ENABLEDSet to true to enable the monthly download and ingestion of Overture Maps POI data.Optional. Default unset
OVERTURE_SYNC_CRONCron schedule for the monthly Overture POI ingestion run.Optional. Default 0 5 1 * * (monthly)

Natural-language search (the search-nlp integration) is configured at /admin/integrations, not in .env. It is cloud-off by default: the provider chain is local, keyword, and a cloud model is used only when it is both listed in the chain and given an API key. If you'd rather pin its config from the environment, use the per-integration override form below (INTEGRATION_SEARCH_NLP_<KEY>) — scalar keys map cleanly; the providerChain array is best set from the admin UI.

VariableDescriptionRequired / Default
INTEGRATION_SEARCH_NLP_PRIVACYMODEstrict (cloud disabled server-side), consent (cloud behind explicit opt-in), or open.Default consent
INTEGRATION_SEARCH_NLP_OLLAMAMODELLocal LLM served by the local-ai (Ollama) service; pulled automatically on first start.Default gemma3:4b-it-qat
INTEGRATION_SEARCH_NLP_OLLAMAENDPOINTOllama base URL. Defaults to the local-ai service URL when that service is enabled.Default http://localhost:11434
INTEGRATION_SEARCH_NLP_ANTHROPICAPIKEYAnthropic key. Required to activate the claude cloud provider; without it the provider is skipped.Optional. Default unset
INTEGRATION_SEARCH_NLP_CLAUDEMODELAnthropic model id for the claude provider.Default claude-haiku-4-5-20251001
INTEGRATION_SEARCH_NLP_OPENAIAPIKEYOpenAI key. Required to activate the openai cloud provider; without it the provider is skipped.Optional. Default unset
INTEGRATION_SEARCH_NLP_OPENAIMODELOpenAI model id for the openai provider.Default gpt-4o-mini

To run the local model, enable the local-ai backend service (Ollama). Its container tuning uses the usual per-service form — LOCAL_AI_MEMORY (default 8g), OLLAMA_KEEP_ALIVE (default 30m), OLLAMA_MAX_LOADED_MODELS (default 1).

Per-integration and per-service overrides

Most integration credentials and per-service knobs are not set here — they are managed in the admin UI, and env values always win over admin-stored ones:

  • /admin/integrations — per-integration detail pages.
  • /admin/integrations/bulk — every integration on one page, plus a generated catalogue (Copy config / Copy credentials / Copy all) you can paste into .env.
  • /admin/services/<id> — per-service config, exposed as SERVICE_<ID>_<KEY> (for example SERVICE_VALHALLA_MEMORY_LIMIT=4g).

Nothing in these override blocks is required at deploy time. Paste only the lines you want to pin from the bulk page; the admin UI generates them on demand so the catalogue stays in sync with the live manifests.

Where to go next