Home | Send Feedback

TileServerGL, a self-hosted map tile server with OpenStreetMap data

Published: July 10, 2018  •  Updated: February 01, 2022  •  selfhost

When you want to add interactive maps to your web application, you need some JavaScript and a server that hosts the map data. A popular solution is Google Maps, where you get an all-in-one package, a JavaScript library, and the map data from Google.

Google Maps is not the only map provider. You can choose others, like Apple Maps and Bing Maps.

And then, there are providers that host maps generated with data from the OpenStreetMap project. The OpenStreetMap data is publicly available, and everyone can use it. On this wiki page, you find a list of commercial companies that provide services around OpenStreetMap data:
https://wiki.openstreetmap.org/wiki/Commercial_OSM_Software_and_Services

The server that sends the map data to a web application is called a tile server. A tile server either serves vector tiles or pre-rendered tiles in PNG format or can support both.

OpenStreetMap itself also runs a tile server (tile.openstreetmap.org) that is used for the map you find on the homepage: https://www.openstreetmap.org
You can use this tile server in your application, but you have to comply with the usage policy: https://operations.osmfoundation.org/policies/tiles/

A better solution is to use one of the commercial providers mentioned above or host your tile server. Fortunately, it is not too complicated to do that. All you need is a server in your intranet or a server connected to the Internet and a lot of disk space. If you run your own tile server, you can either host the whole planet (needs about 51 GB for the base map) or just a region or country.

In this tutorial, I will install a tile server on a VPS. For this demo installation, I used a VPS server from Hetzner (referral link). I chose the smallest server offering: CX11 with 2GB of RAM. For the operating system, I selected Debian 11.

The tile server we will install is called tileserver-gl, an open-source tile server developed and maintained by Klokan Technologies GmbH a Swiss-based company. TileServer GL is written in JavaScript and Node.js. The source code is hosted on GitHub: https://github.com/maptiler/tileserver-gl

The server comes in two flavors, TileServer GL serves vector and raster tiles, and TileServer GL Light without the rasterization component can only serve vector tiles. The server-side rasterization depends on native code that might not run on any platform. TileServer GL Light is pure JavaScript and runs on any Node.js supported platform.

The difference between raster tiles and vector tiles is the location where the map is drawn. When using vector data, the server only sends the raw data to the client, and the client "draws" the map. Yet another benefit is that the data transfer is significantly reduced because vector data is much smaller than rendered images. It is also easy to provide interactivity with map features, and a user can zoom and rotate the map very easily.
Raster tiles are rendered on the server and then transferred to the client as images, usually PNG. This can be beneficial for mobile devices with slow CPU/GPU, where rendering data on the client is slow. The drawback is that the rasterization requires more processing power on the server.

Data

OpenStreetMap data is free to use, and you can download it from different locations. The data is quite big; make sure you have enough space on the disk. Unfortunately, my VPS only has a drive with 20 GB capacity, so I can't download the map data for the whole earth. So instead, I'm downloading only the data for Andorra, a small European country between Spain and France.

The data you download from the OpenStreetMap project is stored in a format that the TileServer GL cannot read. It needs the map data stored in a mbtiles file. MBTiles is a specification for storing arbitrary tiled map data in SQLite databases.

The conversion from the OpenStreetMap raw data into a mbtiles file is time-consuming. Fortunately, we don't have to do that ourselves, and we can download preprocessed mbtiles files from https://data.maptiler.com/downloads/planet/

You have to create a free account before downloading the map data. On the download page, you can search for a region and then download the OpenStreetMap vector tiles.
These files are free for open-source and open-data project websites, non-commercial personal projects, and evaluation and education purposes. In all other cases, you have to buy a license. Visit the pricing page for more information: https://openmaptiles.com/production-package/.

You can either download the file in the browser and transfer it to your server or download it directly on the server. You find a wget command on the download page to execute on the server.

I run all the following commands as a root user. If you are not logged in as root, prepend sudo to the commands or switch to root with sudo -i.

mkdir /opt/maps
cd /opt/maps
wget -c https://data.maptiler.com/download/Wy..../maptiler-osm-2017-07-03-v3.6.1-europe_andorra.mbtiles?usage=personal
mv maptiler-osm-2017-07-03-v3.6.1-europe_andorra.mbtiles\?usage\=personal europe_andorra.mbtiles

In the last section of this blog post, I show you how to create mbtiles files on your computer.

DNS

For this demo installation, I created the maps.rasc.ch domain.
This is optional. You can connect to the server with just the IP address, but you need a domain name if you want to secure the connection with a TLS certificate. And a name is easier to remember than an IP address.

In the web console of my DNS provider, I insert an A record. Also, add an AAAA record if the server has a public IPv6 address.

maps.rasc.ch.        86400   IN      A       51.38.124.133

If you plan to install a TLS certificate, I recommend adding a CAA record. Either for the whole domain if you get all your certificates from one CA or just for the subdomain if you use multiple certificate authorities.

ralscha.ch.             86400   IN      CAA     0 issue "letsencrypt.org"
// OR
maps.rasc.ch.        86400   IN      CAA     0 issue "letsencrypt.org"

TileServerGL

In this section, we install the tile server. But, first, make sure that the system is up-to-date.

apt update
apt full-upgrade

I will run TileServerGL as Docker container, which is the easiest way to install the service on a server. Alternatively, you could install the software directly on Linux.

Install Docker following the installation instructions on this web page:
https://docs.docker.com/engine/install/debian/

Test the Docker installation with docker run hello-world. You should see the Hello from Docker! message if everything is set up correctly.


cd /opt/maps
docker run --restart unless-stopped -d -v $(pwd):/data -p 8080:80 maptiler/tileserver-gl

With --restart unless-stopped, we make sure that the container always runs after a reboot of the server. To stop it, we have to stop it explicitly.

Make sure that you map the local directory where the mbtiles are stored to the /data folder inside the container (-v)

The service listens on the local port 8080. If this port is open in the firewall, you can already connect to the tile server (http://maps.rasc.ch:8080)

Caddy

I want to hide the service behind a web server and enable a secure TLS connection for this installation. You can do this with any web server. A simple solution is Caddy because it automatically manages TLS certificates.

To install Caddy, follow the installation instructions on this page:
https://caddyserver.com/docs/install#debian-ubuntu-raspbian

Open the caddy configuration file.

nano /etc/caddy/Caddyfile 

Insert the following configuration. Change the domain accordingly.

{
   email <valid_email_address_for_lets_encrypt>
}
maps.rasc.ch {
   reverse_proxy localhost:8080
}

Restart caddy

systemctl restart caddy

If everything is set up correctly, you should now connect to the tile server with TLS (https://). In my example https://maps.rasc.ch

Access map from a web application

You can now start developing web applications and use the map data from the tile server.

For this example, I use the MapLibre GL JS library. Check out the documentation page for more information. The source code of the library is hosted on GitHub.

Here is a simple HTML page that displays the map of Andorra. Change the center option accordingly if you have downloaded a different world region.

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8' />
    <title>Map Example</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src="https://unpkg.com/maplibre-gl@2.1.1/dist/maplibre-gl.js"></script>
    <link href="https://unpkg.com/maplibre-gl@2.1.1/dist/maplibre-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>
  const map = new maplibregl.Map({
       container: 'map',
       style: 'https://maps.rasc.ch/styles/basic-preview/style.json',
       center: [1.5813, 42.5341], 
       zoom: 15.65 
  });
</script>

</body>
</html>

You don't need to host this file on a server. Instead, you can create it locally and open it in a browser. Make sure that you change the URL of the tile server.

Convert OpenStreetMap data

The data we can download from OpenStreetMap is stored in a raw format that the TileServer GL cannot read directly; we have to convert it first. In the previous steps, we downloaded the converted data from https://data.maptiler.com/downloads/planet/, but you can convert the data on your computer if you want.

The developers behind the TileServer GL released all necessary conversion tools on GitHub.

Here is an example of how you can convert the OpenStreetMap data of Andorra. I had to install make, git and docker-compose first.

apt install make git
git clone https://github.com/openmaptiles/openmaptiles.git
cd openmaptiles
make
./quickstart.sh andorra

The script runs for a few minutes, depending on the size of the map and the computer's performance; this can take a long time. After the script ends successfully, you find the mbtiles file in the data directory (data/tiles.mbtiles).

By default, the script creates a mbtiles file with data up to zoom level 7. If you need higher zoom levels, open the .env file and modify the zoom settings.

MIN_ZOOM=0
MAX_ZOOM=9

And then run ./quickstart.sh again. Note that higher zoom levels take more time to convert. The maximum zoom level is 14.

Links

TileServer GL documentation:
https://tileserver.readthedocs.io/en/latest/index.html

OpenMapTiles Homepage:
https://openmaptiles.org/

Klokan Technologies, the company behind OpenMapTiles and TileServer GL:
https://www.klokantech.com/