Serving tiles on Heroku

Background

So, spatial data is sometimes a pain. It’s messy, there are a quadrillion file formats and … it’s huge. It is often really, really big. Like … terrabytes big. But even if it’s smaller, it is in most cases way to big to use it in web applications. To circumvent this, you can use tools like mapbox and upload your data to their platform and let it be served via the web from there. But, at a certain point all of these tools cost money and even more so, if you upload more and more data.

Therefore, we will deploy our own tileserver service. There are plenty of tools available to do so, I choose mbtileserver for this. One reason is the file format which is supported by mbtileserver - mbtiles. mbtiles stores the tiles in a compressed format and for every tile it stores the tile data in a separate file. This is a lot of data, but it is much faster to serve. For every combination of zoom level and tile coordinates, there is a file in the mbtiles file (a XYZ file, for raster it’s png, for vector it’s .pbf - imagine it like a svg that you can custamize later on the clientside). These XYZ files are provided at:

<url>/services/<tileset_id>/tiles/{z}/{x}/{y}.<format>

Another nice feature is that you can see a preview of the tileset in the browser:

<url>/services/<tileset_id>/tiles/{z}/{x}/{y}.<format>

You can easily create mbtiles with gdal and store both raster and vector data in them. For example, raster data can be translated like this:

gdal_translate my_dataset.tif my_dataset.mbtiles -of MBTILES
gdaladdo -r average my_dataset.mbtiles 2 4 8 16

Deployment

The deployment basically consists of two steps:

  1. Create a docker image of mbtileserver.
  2. Create a new service on the heroku platform.

Docker

Enough of the theory, let’s get to the real stuff. First, we need a docker file to build the mbtileserver on heroku. This is rather simple:

FROM consbio/mbtileserver

WORKDIR /

COPY . ./tilesets

CMD ["mbtileserver"]

Save this as Dockerfile in a folder.

Heroku

Create a heroku.yml file in the same folder. The following example heroku.yml specifies the Docker image to build for the tileserver’s web process:

build:
  docker:
    web: Dockerfile
run:
  web: bundle exec puma -C config/puma.rb

Now place your mbtiles in the same folder. If you don’t have any, you can start with some beautiful data from Natural Earth:

All that is left now is to deploy the service. To do so, we push our folder to GitHub and then we can deploy the service:

git add .
git commit -m "Init tileserver"
git push
heroku stack:set container
git push heroku master

… et voila! You’re set. The heroku cli should print the adress of your service in the command line, otherwise find it in your heroku dashboard.

More tileserver stuff

The tileserver universum is quite a deep dive, you can find some really cool resources here: