After last weeks overpass api selfhost, this week it is selfhosting openrouteservice.
They have a ready to modify docker-compose.yml and good documentation for Docker hosting.
Maybe a bit too many options and too many choices for someone hosting this the first time.
As last week we will use a Hetzner VPS, I used the same CX32 with 4 cores, 8 GB memory and 80GB disk to start with (and later a CX42 for more memory).
Again I used Debian 12 as operating system.
The 8GB of memory are not enough so we create a swapfile with additonal 8GB of memory:
fallocate -l 8G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
swapon --show
Then I installed Docker Engine.
My modified docker-compose.yml is stripped of everything I don't need: removing car-routing and adding walking.
I downloaded baden-wuerttemberg-latest.osm.pdf
from Geofabrik and put it into a freshly created ors-docker/files/
folder.
---
services:
ors-app:
build:
context: ./
container_name: ors-app
ports:
- "80:8082" # Expose the ORS API on port 80
- "9001:9001"
image: openrouteservice/openrouteservice:v8.0.0
volumes:
- ./ors-docker:/home/ors
environment:
REBUILD_GRAPHS: False
CONTAINER_LOG_LEVEL: INFO
XMS: 4g # start RAM assigned to java
XMX: 10g # max RAM assigned to java. Rule of Thumb: <PBF-size> * <profiles> * 2
# Example: 1.5 GB pbf size, two profiles (car and foot-walking)
# -> 1.5 * 2 * 2 = 6. Set xmx to be AT LEAST `-Xmx6g`
ADDITIONAL_JAVA_OPTS: "" # further options you want to pass to the java command
ors.engine.source_file: /home/ors/files/baden-wuerttemberg-latest.osm.pbf
ors.engine.profiles.car.enabled: false
ors.engine.profiles.walking.enabled: true
Then run everything with docker compose up
.
This took a while. Especially the elevation cache and graph building.
I later tried the pbf for the United States (10GB) which needed more memory (I used a bigger instance with 16Gb of memory and 16GB of swap, and it took more than 7 hours to preprocess.
When the preprocessing is finished, the status page (http://<IP-ADDRESS>/ors/v2/status
) for me looked like this:
{
"languages": [
"cs", "cs-cz", "de", "de-de", "en", "en-us", "eo", "eo-eo", "es", "es-es", "fr", "fr-fr", "gr", "gr-gr",
"he", "he-il", "hu", "hu-hu", "id", "id-id", "it", "it-it", "ja", "ja-jp", "nb", "nb-no", "ne", "ne-np",
"nl", "nl-nl", "pl", "pl-pl", "pt", "pt-pt", "ro", "ro-ro", "ru", "ru-ru", "tr", "tr-tr", "zh", "zh-cn"
],
"engine": {"build_date": "2024-03-21T13:55:54Z", "version": "8.0.0"},
"profiles": {
"profile 1": {
"storages": {
"HillIndex": {"gh_profile": "pedestrian_ors_fastest"},
"WayCategory": {"gh_profile": "pedestrian_ors_fastest"},
"WaySurfaceType": {"gh_profile": "pedestrian_ors_fastest"},
"TrailDifficulty": {"gh_profile": "pedestrian_ors_fastest"}
},
"profiles": "foot-walking",
"creation_date": "",
"limits": {
"maximum_distance": 100000,
"maximum_waypoints": 50,
"maximum_distance_dynamic_weights": 100000,
"maximum_distance_avoid_areas": 100000
}}},
"services": ["routing", "isochrones", "matrix", "snap"]
}
Same as last week an example for how to use the API.
I only needed the routing for a walking distance and duration estimation.
As example we will route from the Empire State building in New York to the center of Central Park.
The coordinates are: 40.748448,-73.985630
to 40.782773,-73.965363
(both lat,lon).
import httpx
r = httpx.get(
"http://<IP-ADDRESS>/ors/v2/directions/foot-walking",
params={
# here it is lon,lat
"start": "-73.985630,40.748448",
"end": "-73.965363,40.782773",
},
)
print(r.json()["features"][0]["properties"]["summary"])
This returns {'distance': 4421.3, 'duration': 3183.2}
, so 4.4 km and 53 minutes.
I compared this to Google Maps Routing and it is in the same ballpark.