Dans le cadre d’un projet, j’ai besoin de faire des requêtes sur les serveurs de Openstreemap, plus précisément les api.
Le problème c’est que les serveurs actuels supportent une belle charge et comme je ne voulais pas prendre trop de place chez eux, je me suis dit, pourquoi pas en monter un moi même.
OSM donnent les instructions pour faire un serveur API de réplication ici : http://wiki.openstreetmap.org/wiki/Overpass_API/Installation
Voici ce que j’ai fait de mon côté sur un serveur OVH SoYouStart
Préparation
On met à jour le serveur
apt-get update && apt-get -y upgrade
On installe les paquets nécessaires
apt-get -y install wget g++ make expat libexpat1-dev zlib1g-dev screen
On va avoir une arborescence de ce type :
/opt/osm -> contiendra les fichiers propres au moteur de recherche
/data/import -> contiendra les fichiers d’import (planet.osm.bz2 par exemple)
/data/db -> contiendra la base de données
/data/diffs -> contiendra les fichiers d’actualisation des données
mkdir -p /data/db mkdir -p /data/import mkdir -p /data/diffs
Compilation
On va récupérer les fichiers sources directement dans /opt/, décomprésser et nettoyer
cd /opt/ wget http://dev.overpass-api.de/releases/osm-3s_v0.7.53.tar.gz gunzip <osm-3s_v0.7.53.tar.gz | tar xvf - mv osm-3s_v0.7.53 /opt/osm rm osm-3s_v0.7.53.tar.gz
On /opt/osm/ contient les fichiers. On va maintenant compiler tout ça
Il est possible d’utiliser la commande screen pour détacher le process et laisser tourner en tâche de fond.
cd osm/ ./configure --prefix="`pwd`" make
Importation des données
On va maintenant importer les données. Importer la planète entière au début n’est pas une bonne idée. Commencez par un petit morceau (la Corse ou le Luxembourg). Vous pouvez récupérer les fichiers sur le site de geofabrik.de.
Si on décide de récupérer la Corse
cd /data/import wget -O corse.osm.bz2 "http://download.geofabrik.de/europe/france/corse-latest.osm.bz2"
Maintenant on va extraire les données et importer les données dans la base. Je vous recommande d’utiliser la commande screen pour ce processus. L’import de la France (3 Go) sur mon serveur a prit 3h30.
cd /opt/osm ./bin/init_osm3s.sh "/data/import/corse.osm.bz2" "/data/db/" "./"
La commande est composée :
/opt/osm/bin/init_osm3s.sh -> le script
/data/import/corse.osm.bz2 -> le fichier d’import
/data/db/ -> l’emplacement de la base de données
./ -> le répertoire de travail
Une fois l’importation terminée, il sera affiché « Update complete » dans la console.
On va donc tester le système avant d’aller plus loin : on lance une console osm
/opt/osm/bin/osm3s_query --db-dir=/data/db
Dans cette console, on va indiquer une requête afin qu’elle soit exécutée. Finir la requête avec Ctrl+D.
Vous pouvez tester la commande suivante pour lister l’ensemble des pubs de la ville de Cologne en Allemagne (mais il faut avoir importé l’Allemangne…)
<query type="node"> <bbox-query n="51.0" s="50.9" w="6.9" e="7.0"/> <has-kv k="amenity" v="pub"/> </query> <print/>
Si vous avez un retour correct (donc pas d’erreurs), c’est que le système fonctionne. Vous pouvez importer une base plus grande, il faut au préalable supprimer l’ensemble des données dans /data/db/
Créer le daemon
On est sous Ubuntu, on va donc créer un script dans /etc/init.d pour créer notre daemon
cd /etc/init.d/ nano overpass.sh
Dans notre fichier, collez ces informations. Attention à bien les modifier si vous avez changé les répertoires !
#!/bin/sh ### BEGIN INIT INFO # Provides: overpass # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Put a short description of the service here # Description: Put a long description of the service here ### END INIT INFO DB=/data/db DIR=/opt/osm DAEMON=$DIR/bin/dispatcher DAEMON_NAME=overpass DAEMON_OPTS="--osm-base --db-dir=$DB" DAEMON_USER=root # The process ID of the script when it runs is stored here: PIDFILE=/var/run/$DAEMON_NAME.pid . /lib/lsb/init-functions do_start () { log_daemon_msg "Cleaning..." rm $DB/osm3s* rm /dev/shm/osm3s* log_daemon_msg "Starting system $DAEMON_NAME daemon" start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS log_end_msg $? } do_stop () { log_daemon_msg "Stopping system $DAEMON_NAME daemon" start-stop-daemon --stop --pidfile $PIDFILE --retry 10 log_end_msg $? } case "$1" in start|stop) do_${1} ;; restart|reload|force-reload) do_stop do_start ;; status) status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $? ;; *) echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}" exit 1 ;; esac exit 0
On sauvegarde, on le rend exécutable et on le configure
chmod +x overpass.sh update-rc.d overpass.sh defaults
On démarre le daemon
/etc/init.d/overpass.sh start
On peut vérifier que le processus est bien démarré
ps aux | grep "dispatcher"
Mise à jour
L’image que vous avez importé dans votre base est une image qui n’est pas à jour. En effet, l’export complet de toute la planète fait aujourd’hui 54Go, et est exportée une fois par semaine.
Pour mettre à jour notre base avec le serveur OSM, il faut importer les différences.
Vous pouvez choisir d’importer les modifications avec une granularité de 1 jour, 1 heure ou 1 minute. Le serveur de mise à jour est http://planet.openstreetmap.org/replication/
Le truc chiant c’est qu’il va falloir dire au serveur depuis quand il n’est plus à jour.
C’est le « replicate sequence number ».
Disons que vous souhaitez mettre à jour votre serveur toutes les minutes et que votre archive date du 31 décembre 2016 à 13h15, alors le nombre magique est 002 252 284 = 2252284.
Le 002 correspond au premier dossier, le 252 correspond au dossier où le fichier 284 se trouve, ce dernier étant l’export à 13h15 le 31 décembre 2016.
On va avoir un script pour récupérer les minutes, chaque minute
nohup /opt/osm/bin/fetch_osc.sh 2252284 "http://planet.openstreetmap.org/replication/minute/" "/data/diffs/" &> nohup-wget.out&
Un script pour mettre à jour la base de données (le –meta est obligatoire)
nohup /opt/osm/bin/apply_osc_to_db.sh "/data/diffs/" 2251284 --meta=no &> nohup-import.out&
Le fait de donner des noms au fichiers nohup c’est pour voir le contenu de temps en temps (tail -f nohup-import.out par exemple)
Web API
On va donc activer Apache et le configurer pour notre api.
apt-get -y install apache2
On active des modules utiles
a2enmod cgi a2enmod ext_filter
On va modifier le fichier de configuration du vhost
<VirtualHost *:80> ServerAdmin webmaster@localhost ExtFilterDefine gzip mode=output cmd=/bin/gzip DocumentRoot /var/www ScriptAlias /api/ /opt/osm/cgi-bin/ <Directory "/opt/osm/cgi-bin/"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Require all granted </Directory> ErrorLog /var/log/apache2/error.log LogLevel warn CustomLog /var/log/apache2/access.log combined </VirtualHost>
On relance Apache
/etc/init.d/apache2 restart
Normalement tout devrait être vert. On va tester l’api avec la commande suivante
wget --output-document=test.xml http://[__IP__ou__domaine__]/api/interpreter?data=%3Cprint%20mode=%22body%22/%3E
Si vous faites un cat test.xml, vous devriez quelque chose du type
<?xml version="1.0" encoding="UTF-8"?> <osm-derived> <note> The data included in this document is from www.openstreetmap.org. It has there been collected by a large group of contributors. For individual attribution of each item please refer to http://www.openstreetmap.org/api/0.6/[node|way|relation]/#id/history </note> <meta osm_base=""/> </osm-derived>
Web API SSL
Tout est déjà opérationnel. Maintenant, si vous souhaitez rajouter une couche de SSL, on va poursuivre en rajoutant un certificat avec Let’s Encrypt par exemple :
apt-get -y install git git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt --depth=1
On demande ensuite le certificat (attention, votre DNS doit déjà pointer sur le serveur !)
/opt/letsencrypt/letsencrypt-auto certonly --webroot -w /var/www/osm.domain.com -d osm.domain.com -m contact@domain.com --agree-tos
Une fois le certificat obtenu, on va configurer apache et le vhost :
a2enmod ssl a2enmod headers
On va rajouter un fichier pour Let’s Encrypt
nano /etc/letsencrypt/options-ssl-apache.conf
Copiez coller le contenu dans votre fichier
# Baseline setting to Include for SSL sites SSLEngine on # Intermediate configuration, tweak to your needs SSLProtocol all -SSLv2 -SSLv3 SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA SSLHonorCipherOrder on SSLCompression off SSLOptions +StrictRequire # Add vhost name to log entries: LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
On va maintenant changer notre fichier vhost
<VirtualHost *:80> ServerName osm.domain.com ServerAlias *.domain.com Redirect permanent / https://osm.domain.com/ </VirtualHost> <VirtualHost *:443> ServerName osm.domain.com ServerAlias *.domain.com ServerAdmin contact@domain.com ServerSignature Off ExtFilterDefine gzip mode=output cmd=/bin/gzip DocumentRoot /var/www/ ScriptAlias /api/ /opt/osm/cgi-bin/ <Directory "/opt/osm/cgi-bin/"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Require all granted </Directory> ErrorLog /var/log/apache2/error.log LogLevel warn CustomLog /var/log/apache2/access.log combined SSLCertificateFile /etc/letsencrypt/live/osm.domain.com/cert.pem SSLCertificateKeyFile /etc/letsencrypt/live/osm.domain.com/privkey.pem SSLCertificateChainFile /etc/letsencrypt/live/osm.domain.com/chain.pem Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains" Include /etc/letsencrypt/options-ssl-apache.conf </VirtualHost>
On redémarre Apache une dernière fois
/etc/init.d/apache2 restart
Le certificat SSL expire tous les 3 mois. On va donc créer un script pour le mettre à jour tout seul
D’abord le fichier /etc/letsencrypt/osm.domain.com.ini
rsa-key-size = 4096 email = contact@domain.com domains = osm.domain.con text = True authenticator = webroot webroot-path = /var/www/
Le script dans /etc/cron.monthly/renew-osm.domain.com.sh
#!/bin/bash /opt/letsencrypt/letsencrypt-auto --config /etc/letsencrypt/osm.domain.com.ini certonly /etc/init.d/apache2 restart
On rend le script exécutable
chmod +x /etc/cron.monthly/renew-osm.domain.com.sh
Dans le doute on peut le tester
/etc/cron.monthly/renew-osm.domain.com.sh
Voilà, vous avez un serveur qui est à jour avec les données OpenStreetMap, qui répond aux requêtes API et en plus protège les données avec un certificat SSL