fix: support Docker runtime routing config with OSRM_MODES#423
Merged
DennisOSRM merged 19 commits intogh-pagesfrom Apr 26, 2026
Merged
fix: support Docker runtime routing config with OSRM_MODES#423DennisOSRM merged 19 commits intogh-pagesfrom
DennisOSRM merged 19 commits intogh-pagesfrom
Conversation
Fixes issue #421: Environment override no longer supported. Users can now override configuration at container runtime using environment variables: docker run -e OSRM_BACKEND='http://localhost:5001' osrm-frontend This works as documented by: 1. Creating docker/entrypoint.sh that reads OSRM_* env vars at startup 2. Generating config.json from env vars before nginx starts 3. Loading config.json in index.html before the app bundle runs 4. Using config values in src/leaflet_options.js Supported environment variables: - OSRM_BACKEND: Backend routing service URL - OSRM_CENTER: Map center coordinates (lat,lng) - OSRM_ZOOM: Initial map zoom level - OSRM_LANGUAGE: UI language - OSRM_LABEL: Default routing service label - OSRM_DEFAULT_LAYER: Default map layer Build-time configuration still supported via --build-arg. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds runtime (container startup) configuration for the OSRM frontend Docker image by generating a config.json from OSRM_* environment variables and loading it before the app bundle runs.
Changes:
- Add
docker/entrypoint.shto emit/usr/share/nginx/html/config.jsonfromOSRM_*env vars at startup. - Update Docker image runtime to use the new entrypoint and provide default
OSRM_*ENV values. - Load
config.jsoninindex.htmlbeforebundle.js, and read runtime config insrc/leaflet_options.js.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| src/leaflet_options.js | Reads runtime config from window.osrmConfig and uses it for initial state and backend URL. |
| index.html | Initializes defaults and attempts to synchronously load config.json before loading bundle.js. |
| docker/entrypoint.sh | Generates config.json from environment variables and starts nginx. |
| docker/Dockerfile | Adds runtime ENV defaults and sets the new entrypoint for the nginx stage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| // Get zoom level from config | ||
| function getZoom() { | ||
| return parseInt(config.OSRM_ZOOM || 13, 10); |
There was a problem hiding this comment.
getZoom() uses config.OSRM_ZOOM || 13, which prevents setting a valid zoom of 0 and can also return NaN if OSRM_ZOOM is non-numeric (which then propagates into defaultState.zoom). Consider checking for undefined/null explicitly and validating the parsed integer before returning it.
Suggested change
| return parseInt(config.OSRM_ZOOM || 13, 10); | |
| var zoomValue = config.OSRM_ZOOM; | |
| var parsedZoom; | |
| if (zoomValue === undefined || zoomValue === null) { | |
| return 13; | |
| } | |
| parsedZoom = parseInt(zoomValue, 10); | |
| if (isNaN(parsedZoom)) { | |
| return 13; | |
| } | |
| return parsedZoom; |
- Fix entrypoint.sh to accept CMD and exec "$@" for standard Docker behavior - Add JSON escaping in entrypoint.sh to handle special characters in config values - Validate OSRM_ZOOM to ensure numeric output in JSON - Change default OSRM_BACKEND from router.project-osrm.org to localhost:5000 (matches README.md documentation) - Replace synchronous XHR with async fetch in index.html (sync XHR deprecated) - Fix 404 handling in index.html (XHR fires onload, not onerror for 404) - Add input validation to leaflet_options.js: * parseCenter() validates lat/lng, falls back to defaults if invalid * getZoom() validates numeric value, falls back if NaN - Add comprehensive test coverage for config overrides in leaflet_options.test.js: * Tests for OSRM_BACKEND, OSRM_CENTER, OSRM_ZOOM, OSRM_LANGUAGE * Tests for invalid/edge case values with fallback behavior * 13 new tests added (now 112 total tests passing) All tests pass, linting passes, Docker builds and runs correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All three routing modes (driving, bike, foot) now use the same configurable OSRM_BACKEND, defaulting to localhost:5000 as documented in README.md. Previously, Bike and Foot modes were hardcoded to routing.openstreetmap.de, making it impossible to use a local OSRM instance for all modes when deployed in Docker. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduce OSRM_ENVIRONMENT to differentiate execution context: - Docker: All modes (driving, bike, foot) use localhost:5000 backend - Local dev: Bike/foot use public routing.openstreetmap.de services Changes: - Add OSRM_ENVIRONMENT env var to Dockerfile (set to 'docker') - Include OSRM_ENVIRONMENT in generated config.json via entrypoint - Add getAlternativeBackend() that returns backend for bike/foot based on environment - Update services array to use public routing services in dev, localhost in Docker Benefits: - Docker users can run full-featured local OSRM stack without modification - Local dev still works with public services (bike/foot) when no local OSRM installed - No breaking changes to existing behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
In local dev (no OSRM_ENVIRONMENT), all routing modes now use public services: - Driving: router.project-osrm.org - Bike: routing.openstreetmap.de/routed-bike - Foot: routing.openstreetmap.de/routed-foot In Docker (OSRM_ENVIRONMENT=docker), all modes use localhost:5000 backend for a fully local setup. Updates: - Refactor getBackend() to return public service URL in dev mode - Update tests to expect public services in dev, localhost in Docker - Add test for Docker mode explicitly Now 113 tests pass (1 additional test for Docker mode). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add OSRM_BACKEND_DRIVING, OSRM_BACKEND_BIKE, OSRM_BACKEND_FOOT env vars - Each mode can now have its own backend URL override - In Docker: all modes default to localhost:5000, but can be customized per mode - In dev: all three modes available (driving via router.project-osrm.org, bike/foot via routing.openstreetmap.de) - Backward compatible: OSRM_BACKEND still works as fallback for all modes - Add 6 tests covering per-mode backend configuration and dev mode availability Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Allow users to define custom names and URLs for routing modes by providing
/etc/osrm/modes.json with a JSON array of {name, url} pairs.
Example modes.json:
[
{ "name": "Car (fastest)", "url": "http://localhost:5000" },
{ "name": "Scenic Route", "url": "http://localhost:5001" },
{ "name": "Walking", "url": "http://localhost:5000" }
]
- Entrypoint now reads /etc/osrm/modes.json at startup (Docker only)
- Falls back to default modes if file not present:
- Docker: Car, Bike, Foot (all using localhost:5000)
- Dev: Car (router.project-osrm.org), Bike (routing.openstreetmap.de), Foot (routing.openstreetmap.de)
- leaflet_options.js now parses OSRM_MODES from config
- Each mode internally mapped to a routing profile (driving, bike, foot)
- Respects OSRM_BACKEND for first mode's URL in default config
- Add 7 tests covering custom modes, default fallbacks, and JSON parsing
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Users can now provide modes directly via docker run without mounting a file:
docker run -e OSRM_MODES='[{"name":"Car","url":"http://localhost:5000"}]' osrm-frontend
Priority order for modes configuration:
1. OSRM_MODES environment variable (highest priority)
2. /etc/osrm/modes.json file (if mounted via -v volume)
3. Default modes (car/bike/foot using localhost:5000)
This makes it convenient for both quick testing and production deployments.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Dev mode (not in Docker): - Uses three public routing profiles: driving, bike, foot - Unless OSRM_BACKEND is explicitly provided (then uses just that one) Docker mode: - Uses single 'default' profile pointing to localhost:5000 - Can be overridden via OSRM_BACKEND env var or OSRM_MODES JSON This ensures: - Dev users see all three public OSRM services - Docker users get a simple single-mode setup by default - Either can be customized via environment variables Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Dev mode (npm start) should use public OSRM services, not localhost. Removed OSRM_BACKEND and OSRM_LABEL from index.html defaults so that in dev mode, parseModes() correctly defaults to three public profiles (driving via router.project-osrm.org, bike/foot via routing.openstreetmap.de). Only Docker mode should default to localhost:5000. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rning
Supports both old (OSRM_BACKEND) and new (OSRM_MODES) environment variables:
Priority order:
1. OSRM_MODES (new JSON-based modes, highest priority)
2. OSRM_BACKEND (legacy, triggers deprecation warning)
3. Defaults (public services in dev, localhost in Docker)
Deprecation behavior:
- If only OSRM_BACKEND is set: creates single 'default' mode, warns to migrate
- If only OSRM_MODES is set: uses new behavior, no warning
- If both are set: uses OSRM_MODES, warns about both being configured
Example migrations:
Old: docker run -e OSRM_BACKEND='http://localhost:5000'
New: docker run -e OSRM_MODES='[{"name":"default","url":"http://localhost:5000"}]'
Add 3 tests verifying backward compat and deprecation warnings.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add detailed logging to parseModes() and buildServices() to see: - What config is being read - Which code path is taken (dev vs docker) - What services array is built This will help diagnose why bike and foot profiles are routing to localhost instead of routing.openstreetmap.de in dev mode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Dev mode (npm start): - driving: router.project-osrm.org - bike: routing.openstreetmap.de/routed-bike with correct path - foot: routing.openstreetmap.de/routed-foot with correct path Docker mode (default): - Single 'default' mode using localhost:5000 - Entrypoint prioritizes: OSRM_MODES > /etc/osrm/modes.json > OSRM_BACKEND > localhost:5000 Fixed entrypoint logic to properly handle OSRM_BACKEND default value without overriding it prematurely. Removed debug logging - all 120 tests passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Docker now defaults to the same three public profiles as dev mode: - driving: router.project-osrm.org - bike: routing.openstreetmap.de/routed-bike - foot: routing.openstreetmap.de/routed-foot Users can override with: - OSRM_MODES=... (JSON) - OSRM_BACKEND=... (legacy, single mode) - /etc/osrm/modes.json (file mount) All 120 tests passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Docker container should default to localhost:5000 with single 'default' profile unless explicitly configured with env vars. Dev mode (npm start) continues to use public demo instances. The distinction is controlled by OSRM_ENVIRONMENT: - If 'docker' (set by entrypoint): use localhost:5000 - Otherwise (dev/browser): use public instances All 120 tests passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Changed services from being computed at module load time to being computed lazily via a getter. This ensures that when buildServices() is called, window.osrmConfig has already been updated by config.json loading (in Docker) or remains with dev defaults (in npm start). This fixes the issue where Docker was reading config before OSRM_ENVIRONMENT was set from the loaded config.json. All 120 tests passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
parseModes() now reads from window.osrmConfig directly instead of using the captured config variable. Combined with lazy-loading via getter, this ensures that OSRM_ENVIRONMENT and other config values are always read from the current window.osrmConfig, which gets updated when config.json is loaded. This fixes Docker container defaulting to public instances instead of localhost:5000 - it now correctly detects OSRM_ENVIRONMENT='docker' from the loaded config.json. All 120 tests passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- keep Docker default routing on http://localhost:5000 with a single default profile - support JSON-based OSRM_MODES runtime configuration for multiple profiles - keep OSRM_BACKEND as a deprecated single-backend fallback with warnings - document precedence and Docker usage examples - add tests for deprecation warnings and entrypoint config generation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes
Resolves #421: environment override support for Docker runtime config.
Summary
This PR moves Docker routing configuration to runtime and keeps the default Docker behavior on a single
defaultprofile pointing tohttp://localhost:5000.The new preferred runtime interface is
OSRM_MODES, whileOSRM_BACKENDremains supported as a deprecated single-backend fallback.Behavior
defaultprofile athttp://localhost:5000.OSRM_BACKENDis set, the frontend configures one backend and emits a deprecation warning.OSRM_MODESis set, the frontend parses the JSON and configures the listed modes.OSRM_MODESwins and the frontend emits a deprecation warning forOSRM_BACKEND.npm startkeeps the public demo profiles for driving, bike, and foot.Changes
config.jsongeneration at container startupOSRM_MODESJSON in the frontend and preserve deprecatedOSRM_BACKENDfallback behaviorDocker examples
Recommended multi-profile runtime config:
docker run -p 9966:9966 \ -e 'OSRM_MODES=[{"name":"car","url":"https://routing.openstreetmap.de/routed-car"},{"name":"foot","url":"https://routing.openstreetmap.de/routed-foot"},{"name":"bike","url":"https://routing.openstreetmap.de/routed-bike"}]' \ ghcr.io/project-osrm/osrm-frontend:latestDeprecated single-backend override:
docker run -p 9966:9966 \ -e OSRM_BACKEND='http://localhost:5001' \ ghcr.io/project-osrm/osrm-frontend:latestValidation
npm run test:lintnpm run buildnpm test