For some web applications is required to add a map to a website. When this is required, many web developers immediately turn to online services hosting the web page. However, for many applications this is not required. It is actually quite easy to generate maps yourself and host them from your own webspace. Using freely available data from OpenStreetmap and using open-source tools it is possible to add beautiful vector graphics maps to your website/webapplication.

In this post I would like to explain how maps can be generated from openstreetmap using tilemaker. This is mostly suited for hosting regional exports, hosting the complete planet still requires significant amounts of storage (60G).

The openstreetmap data we will be using in this tutorial is:

And the openstreetmap tools:

Finally for the frontend:

The steps required to add an openstreetmap vector to your map are as follows:

  • Create a regional export of the openstreetmap data for the region you want to add to your page
  • Generate the tiles from the regional openstreetmap extract
  • Install the tileserver-php to host the tiles on your server
  • Create the html page that displays the tiles using mapbox gl js

Please note that creating large maps (country size) reguires significant memory to generate the map (8 to 16G).

Creating a regional export

First step we need to do is create an export of the region we would like to host. It is possible to download the complete openstreetmap of the full planet here: Planet OSM.

This file is quite big (around 60G) and will take some time to download and to process. It is possible to get pregenerated exports from here: GeoFabrik.

Even country extracts are available on this website. This can reduce the processing time and downloading time significantly. Note however, that if we would like to export a region (for example Netherlands), we would actually like a rectangular export. So we would like to include also some parts around the border. The exports from geofabrik are extracted around the borders of the country and bordering countries will appear as gray areas if we bound the map to a rectangular area.

So we decided we would like to export a country, for example Netherlands. We can create a nice rectangular cut-out from a larger region (for example Europe) and generate this. The extract (cut-out) we can create with a tool called osmium. So we download the Europe area first from GeoFabrik, and the next step is to determine the bounding box of the region we would like to extract.

GeoFabrik has a nice tool available to determine the bounding box, it is available from here: GeoFabrik Calc. Using this tool I select a rectangle around The Netherlands, and the lat/lon coordinates of this bounding box are available from the 'Coordinate Display' tab, from the field 'Simple Copy'. The bounding I have selected is: 2.68 50.72 7.55 54.12

On Ubuntu I can now install the osmium tool using:

sudo apt-get install osmium-tool

or on MacOS:

brew install osmium-tool

To create the regional export run:

osmium extract --bbox=2.68,50.72,7.55,54.12 --set-bounds --strategy=smart europe-latest.osm.pbf  --output netherlands.osm.pbf

For Windows you can use the OSMConvert tool:

osmconvert europe-latest.osm.pbf -b=2.68,50.72,7.55,54.12 --complete-ways -o=netherlands.osm.pbf

It takes some time and memory, but after this, you will have a nice rectangular extract of the region you would like to host.

Generating tiles from the extract

Next step we want to do is generating the vector tiles from the regional extract. For this we will be using Tilemaker. It is possible to build this project yourself, but precompiled binaries are available here.

Download and extract the file:

wget https://www.kleunen.nl/tilemaker-tutorial/tilemaker.tar.gz
tar xvzf tilemaker.tar.gz

We also need data from international waters and coastlines:

wget https://osmdata.openstreetmap.de/download/water-polygons-split-4326.zip
unzip water-polygons-split-4326.zip

You can now start generating the map using tilemaker:

./linux/tilemaker --input netherlands.osm.pbf --output netherlands.mbtiles --process resources/process-openmaptiles.lua --config resources/config-openmaptiles.json 

Based on the size of the extract, this can take from several minutes to several hours and may use significant memory, up to many gigabytes. Start therefore with a small region export. When the conversion is finished, tilemaker will say:

Filled the tileset with good things at netherlands.mbtiles

We are now ready to start hosting these tiles.

Hosting the tiles

For hosting the tiles we need a webserver with php enabled. Also, the php should have sqlite enabled, the mbtiles files is a sqlite database file which will be opened by our tileserver. For hosting the map, we will be using Tileserver-php. Clone this repository with git on your webserver:

cd /var/www/html
git clone  https://github.com/maptiler/tileserver-php

Copy the mbtiles file into the directory of tileserver-php:

cp netherlands.mbtiles /var/www/html/tileserver-php

If you use the apache webserver, all things are set now. If you use nginx, you need to add url rewriting rules to the nginx configuration:

location /tileserver-php/ {
    try_files $uri /tileserver-php/tileserver.php$is_args$args;
}

If all things went correctly, you can open the url to tileserver-php and see your map. Tileserver PHP

Display the page on your website

Now we are ready to use the generated tiles on our own website. For this, we will be using the Mapbox GL JS library together with a style from OpenMapTiles

Create a small webpage displaying the map:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Display a map on a webpage</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css" rel="stylesheet" />
<style>
    body { margin: 0; padding: 0; }
    #map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>

<script>
var bounds = [ [2.68, 50.72], [7.55, 54.12] ];

mapboxgl.accessToken = 'pk.eyJ1Ijoid2tsZXVuZW4iLCJhIjoiY2lvYndseWF4MDA1NXZqbTVsNzI1cTZxZSJ9.OiaID7onSRgGBWRwmgOZqQ';
var map = new mapboxgl.Map({
  container: 'map',
  center: [ (bounds[0][0] + bounds[1][0]) / 2, (bounds[0][1] + bounds[1][1]) / 2],
  zoom: 9,
  minZoom: 5,
  style: 'netherlands_style.json',
  maxBounds: bounds 
});

map.addControl(new mapboxgl.NavigationControl());
</script>
</body>
</html>

You also need to install the netherlands_style.json file. You can download it from this blog or use another style from OpenMapTiles.

Inside this file you need to edit two URLs to point to your tileserver. The name 'netherlands.json' corresponds with the file 'netherlands.mbtiles'.

  "sources": {
    "openmaptiles": {
      "type": "vector",
        "url": "https://www.kleunen.nl/tileserver-php/netherlands.json"
    }
  },
  "glyphs": "https://www.kleunen.nl/fonts/{fontstack}/{range}.pbf"

And you need to install the fonts onto your server:

git clone https://github.com/klokantech/klokantech-gl-fonts fonts
ln -sf 'KlokanTech Noto Sans Bold' fonts/Bold
ln -sf 'KlokanTech Noto Sans Regular' fonts/Regular

If all is well, you should see now your own hosted map. Read further here to learn how to improve hosting speed.