Installer Overpass API

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