TileServer GL: Maps with GL JSON styles from your server

New open-source project TileServer GL has just been released in version 1.0 at the FOSS4G conference and is available on our GitHub:


With TileServer GL you can host vector tile maps on your own infrastructure, under your control, or even completely offline. The software takes care of serving the vector maps (PBFs, GL JSON styles, and all the assets), but also provides server-side rasterized tiles as a fallback.

Raster tiles look exactly the same as vector maps and are generated from vector tiles and GL JSON style on the server side with the MapBox GL Native rendering core made in C++.

The vector tiles allow for nicer maps, with a higher degree of interactivity and also decrease bandwidth to your server. The vector maps can be used in several web mapping libraries such as MapBox GL JS or OpenLayers 3 as well as native mobile applications for Android or iOS. The raster tiles can be used in almost any software including Leaflet or GIS tools (via XYZ, TileJSON, WMTS).

This way you can transition to the vector tiles wherever possible, but still have the raster tiles with the same look & feel without the need to write the map style twice in a different format.

The server can be easily set up to provide several different styles (in a modern GL JSON format), so you can have multiple maps for different use cases served from a single set of vector tiles. There are also endpoints serving static raster maps with the possibility to add polygon overlays simply by adding parameters to the URL. All the endpoints support scaling parameters so you always have HiDPI/retina, print-ready maps at your disposal.

The TileServer GL relies on other open-source projects, which have been under development for years. Most notably mapbox-gl-native, which we use for the server-side rendering and mapbox-gl-js which is default viewer for vector tiles.

This video shows in the first two minutes how easy it is to run your own map server using TileServer GL with open-data tiles downloaded from OSM2VectorTiles:

All what you need is a single docker command:

docker run -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl

Feel free to try our TileServer GL live instance at https://maps.klokantech.com/.

It's also possible to combine multiple input sources (MBTiles; tiles from Amazon S3 or GCS; dynamic tiles from GeoServer, MapServer, ...) to create complex or even hybrid maps (satellite maps with labels). The whole stack is usable with custom coordinate systems as well!

If you are interested to know more watch the complete video recording of our presentation from FOSS4G at https://youtu.be/rOg4VnSAnI4.

Considering transition to vector tiles? Do you want production deploy of TileServer GL? Need to render your own vector or raster tiles? Contact us at info@klokantech.com!


Blue-Green Deployment with Docker and Nginx

Here at Klokan Technologies, we mostly develop software services and we run them as Docker containers. To release new versions, we use the blue-green deployment technique. This reduces downtime and limits the impact of configuration errors.
The basic idea is simple. Instead of having just one production environment, there are two identical ones: blue and green. They take turns actively running the service. A new version is deployed to the environment that is not currently active. Only after the service successfully starts up there and passes all health checks is that environment marked as active. The old active environment is then stopped and prepared to receive the next deployment.
The switch from one environment being active to the other one is a crucial step. If it’s not atomic, there will be a short period where neither environment is active and any request coming in at this time will fail. We use Nginx for this purpose because it does have this capability and because we have it as a reverse proxy anyway.


To illustrate the whole process, let us consider an example. We will deploy a Python application in a file called hello.py, listed below. It listens for HTTP requests on port 9000 and responds with a greeting, providing a simple service.

$ cat hello.py
from wsgiref.simple_server import make_server

GREETING = b'Hello, world!\n'

def hello(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/plain')])
    return [GREETING]

make_server('', 9000, hello).serve_forever()

We will have one container for the application and one for Nginx. We will put both on the same Docker network, so that they can see each other. In our production environment, we have separate backend and frontend networks, but it is not necessary here. We will use official Docker images.

$ docker network create example
$ docker pull nginx
$ docker pull python:3

First we start the application itself in the BLUE environment. Notice that we name the container hello-BLUE.

$ docker run \
    --name hello-BLUE \
    -v $(pwd)/hello.py:/usr/local/src/hello.py \
    --net=example \
    -d \
    python:3 \
    python /usr/local/src/hello.py

Then we put the application configuration for Nginx into a file called nginx-conf.d/hello.conf. It sets up an HTTP proxy that forwards all requests to the application. Here again, we have to refer to the application container as hello-BLUE.

$ cat nginx-conf.d/hello.conf
server {
    listen 80;
    location / {
            proxy_pass http://hello-BLUE:9000;

Now we can start Nginx. It will read the configuration file we have just created and publish the application proxy on port 8080.

$ docker run \
    --name nginx \
    -v $(pwd)/nginx-conf.d:/etc/nginx/conf.d \
    --net=example \
    -p 8080:80 \
    -d \

See that it works.

$ curl http://localhost:8080
Hello, world!

Now we make a new version of the service by changing the greeting in the hello.py file.

$ cat hello.py
from wsgiref.simple_server import make_server

GREETING = b'Hello, world! (VERSION 2)\n'  # <=== Change here

def hello(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/plain')])
    return [GREETING]

make_server('', 9000, hello).serve_forever()

We start the application again, this time in the GREEN environment. Notice the change in the container name. Otherwise the command is the same as before.

$ docker run \
    --name hello-GREEN \  # <=== Change here.
    -v $(pwd)/hello.py:/usr/local/src/hello.py \
    --net=example \
    -d \
    python:3 \
    python /usr/local/src/hello.py

We have to change the name of the application container in the Nginx configuration as well.

$ cat nginx-conf.d/hello.conf
server {
    listen 80;
    location / {
            proxy_pass http://hello-GREEN:9000;  # <=== Change here

Before switching active environments, we must check that the configuration is correct and that the application is reachable. There is an Nginx command line option for that, so we run it in a temporary container.

$ docker run \
    --rm \
    -v $(pwd)/nginx-conf.d:/etc/nginx/conf.d \
    --net=example \
    nginx \
    nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If the check was successful we send the Nginx container a SIGHUP signal. This will make it re-read the configuration and restart itself without dropping any requests.

$ docker kill -s HUP nginx

And we can see that we have a new version deployed.

$ curl http://localhost:8080
Hello, world! (VERSION 2)

The BLUE environment is no longer needed, so we remove it.

$ docker stop hello-BLUE
$ docker rm hello-BLUE


In our example, we only had one application container for the service. There could be more and they would all be manipulated together. There could also be more services running on the same machine. They would each have its own BLUE and GREEN environments.
The Nginx container and other infrastructure containers with state are not deployed using this technique. This includes databases and most caches. We can’t stop or restart databases because the active environments are using them even during the switch, and we usually don’t want to clear caches on each deployment.
There is more to making this approach viable for automated deployment. We haven’t mentioned how to determine which environment is currently active for a given service and machine. Also, manually editing configuration files before each deployment is clearly not the way to go. At Klokan Technologies, we actually use Ansible with a custom module to solve both problems, but that is a story for another day.


PDFium GeoPDF driver in GDAL 2.1

GDAL is a very popular open-source library for decoding/encoding of geospatial data formats and raster processing. It is used by QGIS, Grass, MapServer, but also by Google Earth or ESRI ArcGIS and many other GIS software tools. It powers our MapTiler software too.

A new implementation of efficient reading of PDF and GeoPDF file formats is available in GDAL library since version 2.1. Klokan Technologies GmbH team is behind the implementation of this format driver, which has been accepted and merged by Even Rouault and released publicly in May 2016.

The driver is powered by the open-source PDFium library, which has been released by Google Inc. for easier previewing of the .pdf files used in the open-source Chrome/Chromium browser. The free PDFium library is BSD licensed light version of the PDF Foxit framework. We have prepared compiling scripts for Linux, Mac OS X and Windows, which were adopted, included and documented as part of the GDAL.

The advantages of the new PDF driver:
  • Significantly higher performance (compared to the previous PoDoFo and Poppler engines)
  • Support for larger PDF files with smaller memory footprint - even large AutoCAD plans or huge GeoPDFs can be processed efficiently now.
  • A non-restrictive BSD license! The copy-left GPL prevented the existence of applications supporting both PDF and MrSID/ECW formats for example.

The driver is in production use in our MapTiler software for over a year now.

We are pleased to share the source code with the community and offer it for integration in all open-source projects and third-party products. Next time, when you launch your favorite open-source GIS tool after the GDAL library has been updated, you may benefit from the faster PDF reading thanks to our work!


MapTiler 7: Auto-save and new georeferencing

New georeferencing interface

The visual georeferencing process was completely redesigned. Scanned maps and images missing geographical location can be positioned directly. There is a new Overlay option, where it is possible to toggle between the image and background map with a Shift button. Adding more control points this way is faster and more precise - and the overlay is immediately recalculated.

It is possible to preview the exact location of the whole map before rendering the map tiles!

Five transformations are available for the best fit and users needs: Scaled, Similarity, Affine, Polynomial, TPS:
You can type coordinates numerically, and all EPSG spatial reference systems are supported out of the box!

Auto-save of the georeference

When a file is reopened, previous manually done georeference is again loaded on the same computer. This saves time on scanned maps, that have been already georeferenced and only need rerendering or further adjustments.

Other new features

Next to the improvements in the georeferencing process, there are several new features, and improvements coming with MapTiler 7:
  • Map portal with your logo and maps is online with one click, hosted on Amazon or Google cloud! More details in a future blog post.
  • Retina/HighDPI tiles (@2x and @3x) with ready to use OpenLayers viewer on all map profiles, including raster!
  • Background map added to MBTiles preview on Desktop (just double-click on a .mbtiles file!)
  • Shortcut icons for easy upload of the maps to mobile app and to cloud hosting
  • Legend, including image, stored in metadata of generated MBTiles maps 
  • HTTPS hosting on Amazon S3 and Google Cloud Storage offered directly
  • Now unavailable MapQuest maps were replaced with our own OpenStreetMap base maps
And, from now on we have versions without zero in the beginning - so after 0.6.4 comes now 7.0!

Do you want to try the latest MapTiler? Get it for free at http://www.maptiler.com/


NOAA pilots use Open-source Tileserver

Open source software Tileserver.php developed by Klokan Technologies helps NOAA pilots to acquire new aerial imagery.

The base maps pre-rendered with MapTiler are stored on a small Intel NUC I7 on board, where tileserver.php is installed. Via local Wifi, the maps are streamed to an iPad attached to a pilot dashboard showing the position of an airplane and exact area of a taken photography.

The system is in active use and was presented by Jon Sellars and Jason Woolard from NOAA on FOSS4G NA 2016. The presentation is available at https://2016.foss4g-na.org/sites/default/files/slides/FOSS4GNA_2016_ONAV_v4.


Open-source software used for hosting of maps on the board:

MapBox GL JS

The open-source library used for displaying free OpenStreetMap vector tiles (http://www.osm2vectortiles.org/).


Software used for pre-rendering of the aerial imagery into raster tiles.


Rotation of a map in Georeferencer

Some of the historical maps are unfortunately not north-oriented. To turn the map while georeferencing will save time and help to find the depicted places.

In the new user interface, it is possible to rotate the map while holding Alt+Shift.

The rotation is also automatically calculated after you assign first two ground control points on a map!

This feature will make the georeferencing easier and more convenient for the users. The rotation feature is now developed, applied in the Cynefin pilot project (http://cynefin.archiveswales.org.uk/), and it is going to be a part of the next generation of Georeferencer service.

Following short movie shows the rotation feature:


TileServer-PHP version 2.0

New version of the open-source project TileServer-PHP has just been released and is available at https://github.com/klokantech/tileserver-php

The project distributes maps to desktop, web, and mobile applications from a standard Apache+PHP web hosting. It implements OGC WMTS standard for pre-rendered map tiles made with MapTiler or available as MBTiles files.

The new features include:

MapBox Studio Classic vector tiles supported

Hosting of vector tiles in MBTiles format generated by MapBox Studio Classic is possible on a custom server with TileServer-PHP. Users can also download ready-to-use OpenStreetMap vector tiles from http://osm2vectortiles.org/downloads/ and style them with MapBox Studio Classic!

TileServer-PHP can serve the vector tiles to OpenLayers, MapBox GL JS and native Android or iOS apps.

Custom designed templates

To change look&feel of the TileServer-PHP frontpage with your own design, branding, and functionality see https://github.com/klokantech/tileserver-php/wiki/Template

WMTS for tiles in any coordinate system

MapTiler can generate tiles in a custom map projection or country specific coordinate systems (such as UK’s Ordnance Survey EPSG:27700 or Swiss CH1903 / LV03 EPSG:21781).
TileServer-PHP now serves these tiles to any GIS software via OGC WMTS standard.
Draft of an extension of TileJSON with support for custom projections is at https://github.com/klokantech/tilejson-spec/tree/custom-projection/2.2.0

Hybrid and WebP map tiles 

Hybrid tiles (JPG+PNG) where partly transparent tiles can be combined with opaque ones in one layer are supported. This solution and new WebP format are mostly used on satellite imagery to reduce the size.

TileJSON and WMTS for remote tiles

Serving WMTS or TileJSON for remote tiles hosted on Amazon S3 or Google Cloud Storage.  As an online service already runs on http://wmts.maptiler.com/. Upload is quick and easy with MapTiler: http://www.maptiler.com/how-to/hosting-on-amazon-s3/