Cet article explique comment mettre en place un serveur de routage (calcul de route entre deux points) à partir de données OpenStreetMap, en s’appuyant sur GraphHopper. L’objectif est d’obtenir une API HTTP (ex. /route) utilisable depuis une application web, mobile ou un back-end.
On abordera :
-
les outils disponibles (SaaS vs auto-hébergé),
-
l’installation de GraphHopper,
-
le téléchargement/fusion des données OSM,
-
la configuration (profils, optimisations CH/LM, élévation),
-
l’import, le déploiement et l’exposition via Nginx + systemd,
-
les tests et points de performance.
Outils et alternatives
Avant d’auto-héberger, voici deux solutions populaires :
-
GraphHopper : https://www.graphhopper.com/
-
OpenRouteService : https://openrouteservice.org/
Pour tester rapidement l’API GraphHopper (explorateur) :
Tutoriels et docs utiles
-
GraphHopper (auto-héberger un calculateur mondial) : https://www.graphhopper.com/blog/2022/06/27/host-your-own-worldwide-route-calculator-with-graphhopper/
-
Installation GraphHopper : https://github.com/graphhopper/graphhopper#installation
-
Installation OpenRouteService depuis les sources : https://giscience.github.io/openrouteservice/installation/Building-from-Source.html
1) Installation de GraphHopper
Pré-requis : Java (JRE + JDK)
GraphHopper est une application Java. Il faut un environnement Java complet.
Installer le JDK (inclut ce qu’il faut pour exécuter et compiler) :
sudo apt install -y default-jdkVérifier les versions de Java et du compilateur :
java -version javac -versionTélécharger GraphHopper
On récupère :
-
le jar « web » (serveur HTTP),
-
un fichier de configuration d’exemple.
Tracez votre propre parcours
MapPlanner vous aide à calculer les distances, le dénivelé, la durée et à planifier vos randonnées, courses à pied et sorties vélo sur une carte interactive.
- Calcul automatique des distances et du dénivelé
- Cartes topographiques, satellite et IGN
- Export GPX/KML pour votre GPS
- Suivi GPS en temps réel
2) Télécharger les données OpenStreetMap (OSM)
GraphHopper calcule des routes à partir de données OSM au format PBF (.osm.pbf).
Téléchargement par zone (ex : Europe, France, etc.) :
Cas multi-fichiers : fusionner plusieurs PBF
GraphHopper n’accepte pas plusieurs fichiers PBF en entrée directe. Si vous voulez couvrir plusieurs régions (ex : Europe + Amérique du Nord), il faut fusionner les PBF en un seul.
Important :
-
idéalement, éviter les zones qui se chevauchent, sinon risque d’incohérences.
Installer osmium :
sudo apt-get install osmium-toolFusionner :
osmium merge europe-latest.osm.pbf north-america-latest.osm.pbf -o map.osm.pbfEnsuite, vous indiquerez map.osm.pbf dans la configuration GraphHopper.
3) Configurer GraphHopper
GraphHopper est piloté via un fichier YAML.
Copier le fichier d’exemple :
mv config-example.yml config.ymlProfils de routage (car, foot, hiking, …)
Les profils définissent le comportement : voiture, marche, rando, vélo…
Doc profils :
Custom models
Les custom models permettent d’ajuster les règles (types de routes, préférences, pénalités…).
-
modèles disponibles :
https://github.com/graphhopper/graphhopper/tree/master/core/src/main/resources/com/graphhopper/custom_models -
documentation détaillée :
https://github.com/graphhopper/graphhopper/tree/master/docs/core
4) Optimisations de calcul : CH vs LM vs “par défaut”
GraphHopper peut pré-calculer des structures d’accélération pendant l’import.
Deux modes cités :
-
profiles_ch : le plus rapide en requête, mais coûteux en RAM et en temps d’import.
-
profiles_lm : plus flexible, permet de customiser en partie lors des requêtes.
Points importants (résumé pratique) :
-
CH :
-
requêtes très rapides,
-
import plus long (souvent ×10),
-
plus de RAM,
-
moins flexible (pas de customisation de profil à la requête).
-
-
LM :
-
bon compromis,
-
permet des requêtes avec paramètres (custom model dynamique),
-
plus lent que CH mais plus souple.
-
Si CH est activé, il est conseillé d’activer :
-
turn_costs: false
(réduit fortement le temps de génération d’un profil, et accélère les requêtes)
À noter : ajouter plusieurs profils proches augmente généralement peu la RAM (profils se recoupent), mais chaque profil LM peut peser lourd sur disque.
5) Ajouter l’élévation (dénivelé)
GraphHopper peut enrichir le graphe avec des données d’altitude.
Doc :
Modes disponibles (+ un mode caché) :
-
srtm : 3.1Go sur disque en compressé, données très peu précises
-
cgiar : 3.2Go sur disque en compressé, données approximatives mais avec moins d'incohérences que srtm
-
gmted : non testé
-
multi : non testé
-
SRTMGL1 : URL non accessible mais données précises
Principe :
-
vous indiquez un mode (ex srtm) dans la config,
-
GraphHopper télécharge automatiquement les tuiles d’élévation nécessaires pour la zone couverte.
6) Importer les données dans GraphHopper
L’étape d’import convertit les données OSM en un graphe optimisé exploitable par le serveur.
Commande d’import (avec mémoire dédiée) :
java -Xms62g -Xmx62g -jar *.jar import config.ymlPourquoi import ?
-
plus optimisé pour la conversion,
-
libère la mémoire après import,
-
ne démarre pas le serveur.
Données générées :
-
un répertoire graph-data contient le cache et les données importées.
Important :
-
si vous changez les profils ou mettez à jour le PBF, il faut souvent supprimer graph-data avant de réimporter.
Temps d’import observés
-
Europe : 45m et 38Go de RAM dédiée pour une taille sur disque de 12Go (sans profils d'optimisation et Ryzen 3800X)
-
Europe et Nord Amérique : 92min et 58Go de RAM sans profils d'optimisation pour une taille sur disque de 27.2Go (5 profiles : car, foot, hike, bike et mtb)
-
Europe et Nord Amérique : 12h et 62Go de RAM avec un profil LM d'optimisation (avec un seul LM : 9h10min et 46Go) pour une taille sur disque de 60Go (chaque profile LM prend 14Go)
-
Europe et Nord Amérique : 7h50 avec élévation et sans profile d'optimisation pour 30.2Go
-
Europe et Nord Amérique : 7h avec élévation cgiar sans profile d'optimisation avec 2 profils en plus pour 30.2Go (les profils supplémentaires n'ont pas d'impact sur la taille finale ni sur le temps de génération)
7) Mettre à jour la base de données
Vérifier les releases GraphHopper :
Si besoin, mettre à jour la config et les profils :
-
config d’exemple :
https://github.com/graphhopper/graphhopper/blob/master/config-example.yml -
attention au nommage des custom models.
Lancer la mise à jour :
./generate_routing.shMettre à jour puis redémarrer côté serveur :
nano config.yml nano custom_models/* sudo nano /etc/systemd/system/routing.service sudo systemctl daemon-reload sudo systemctl restart routing.serviceAjuster si besoin la mémoire Xmx (ex. -Xmx28g).
8) Déployer GraphHopper (serveur HTTP)
Doc de déploiement :
Lancer le serveur (Europe)
Minimum recommandé (sans CH/LM) :
java -Xmx18g -jar *.jar server config.ymlEurope + Amérique du Nord (exemple)
/usr/bin/java -Xmx32g -XX:+UseZGC -jar graphhopper-web-11.0.jar server config.ymlNote :
-
*.jar peut être pratique en mise à jour (remplacement du jar).
9) Requêtes avec paramètres personnalisés (custom model dynamique)
Si le mode LM est activé pour un profil, on peut envoyer une requête POST sur /route pour ajuster des paramètres.
Point clé :
-
il faut bien indiquer ch.disable=true pour forcer l’utilisation du mode LM.
Cas d’usage :
-
choisir “plus rapide” vs “plus court”,
-
exclure certains types de routes.
Attention :
-
les poids/valeurs envoyées ne peuvent être que supérieures à la configuration initiale.
Règle simple pour distance_influence :
-
“plus rapide” : valeur la plus basse possible (1 = plus petit)
-
“plus court” : valeur la plus haute (100 ou supérieur)
10) Optimisation mémoire : MMAP (ne pas tout charger en RAM)
Par défaut, GraphHopper peut stocker beaucoup en mémoire. Pour réduire la pression RAM, on peut utiliser un accès mémoire mappé fichier.
Dans la config :
graph.dataaccess.default_type: MMAPAu lieu de RAM_STORE.
Effets :
-
utilise ~50% de la RAM définie dans -Xmx,
-
démarrage plus rapide,
-
requêtes plus lentes.
Autre point :
-
après import, le fichier PBF n’est plus requis.
11) Exposer l’API via Nginx (reverse proxy + CORS)
Exemple de config Nginx (proxy vers le port 8989) et indiquer le bon nom de domaine :
server { listen 80; listen [::]:80; server_name routing....com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name routing...com; include snippets/l-x-ssl.conf; access_log /var/log/nginx/routing_access.log; error_log /var/log/nginx/routing_error.log; root /home/www/graphhopper; location / { proxy_pass http://127.0.0.1:8989; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Protocol $scheme; proxy_set_header X-Forwarded-Host $http_host; # Ajouter les headers de contrôle d'accès CORS proxy_hide_header 'Access-Control-Allow-Origin'; add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding' always; add_header 'Access-Control-Allow-Credentials' 'true' always; } # Disable access to front page location = / { deny all; } # This header tells web browsers not to cache the CORS reponse header. add_header 'Vary' "Origin"; # This controls which domains can use this tile server via CORS. It's like an access control list. # add_header "Access-Control-Allow-Origin" "https://www.example.com"; # If you want to allow all domains to use your tile server, then comment out the above line and uncomment the following line. add_header "Access-Control-Allow-Origin" "$http_origin"; }Accès ensuite au domaine indiqué dans la configuration pour tester et valider.
12) Créer un service systemd (démarrage automatique)
Créer le service :
sudo nano /etc/systemd/system/routing.serviceContenu :
[Unit] Description=Graphhopper Routing After=network.target [Service] Type=simple User=lx Group=lx WorkingDirectory=/home/www/graphhopper ExecStart=/usr/bin/java -Xmx16g -jar graphhopper-web-8.0.jar server config.yml # if we crash, restart TimeoutSec=30 Restart=on-failure RestartSec=5s #Type=notify #NotifyAccess=all TimeoutStartSec=120 TimeoutStopSec=30 # output goes to /var/log/syslog StandardOutput=journal StandardError=journal # This will default to "bundler" if we don't specify it SyslogIdentifier=routing [Install] WantedBy=multi-user.targetActiver et démarrer :
sudo systemctl daemon-reload sudo systemctl enable routing.service sudo systemctl start routing.service13) Tests rapides
Test en local :
curl "http://localhost:8989/route?profile=foot&point=52.5300591%2C13.3565022&point=52.5060440%2C13.4378107"14) Référence API GraphHopper
Doc officielle de l’API web :
https://github.com/graphhopper/graphhopper/blob/master/docs/web/api-doc.md