Provide a practical and easy-to-follow tutorial on how to set-up TileServerGL for:
- [A] Providing background maps
- [B] Providing Data as vector tiles to be consumed client-side via MapboxGLJs
TileServerGL is a vector and raster tile server developed by KoklanTechnologies, capable of "server side rendering by Mapbox GL Native. Map tile server for Mapbox GL JS, Android, iOS, Leaflet, OpenLayers, GIS via WMTS, etc."
While the installation is fairly straightforward (just install docker + run docker run --rm -it -v $(pwd):/data -p 8080:80 klokantech/tileserver-gl
and docker will automatically download the container+test dataset and start it ), the actual customisation proves a bit more tricky due to patchy documentation and banal yet annoying issues such as relative paths, docker volume mounting etc...
In particular, the customisation requires at least:
config.json
specifying the likes of data sources (both for styling and data provision), fonts, stylying file.style.json
such as the famous BrightOSM styling file, Positron etc... NOTE: such files holds a further reference to the data source corresponding data source (in mapboxGLJs every styling is formalised in a json style file decoupled from the actual raw data)
The problem resides in the relative paths
Let me exemplify:
- In the
config.json
one can specify
- The relative paths in
paths
object
"paths": {
"root": "",
"fonts": "fonts",
"sprites": "sprites",
"styles": "styles",
"mbtiles": ""
},
According to the docs
paths
defines where to look for the different types of input data. The value ofroot
is used as prefix for all data types.
- The path to the styling file should then added in the
styles
option
"styles": {
"basic": {
"style": "basic.json",
"tilejson": {
"type": "overlay",
"bounds": [8.44806, 47.32023, 8.62537, 47.43468]
}
},
- Similarly, the data path can be then added in the
data
option:
"data": {
"zurich-vector": {
"mbtiles": "zurich.mbtiles"
}
}
- Further, in the styling file (e.g.
styles/positron-gl-style/style.json
), there's a further necessity to explicitly point to the data, fonts and sprite files:
"sources": {
"openmaptiles": {
"type": "vector",
"url": "mbtiles://data/italy.mbtiles"
}
},
"sprite": "https://openmaptiles.github.io/positron-gl-style/sprite",
"glyphs": "fonts",
- Lastly, the preceding paths should be integrated with docker's volumes when launching the dockerised tileserver instance.
Such command can be for instance the following:
docker run -it -v $(pwd)/data:/data -v $(pwd)/styles:/styles -v $(pwd)/fonts:/fonts -p 3001:80 klokantech/tileserver-gl -c config.json --verbose
which in theory should mount local folders to their respective counterparts in the container. The above is assuming the follwing directory structure:
➜ tileserver-gl l
total 24M
drwxr-xr-x 5 root root 4.0K Dec 6 21:39 .
drwxr-xr-x 14 root root 4.0K Dec 6 13:58 ..
-rw-r--r-- 1 root root 504 Dec 6 21:40 config.json
drwxr-xr-x 2 root root 4.0K Dec 6 15:26 data
drwxr-xr-x 3 root root 4.0K Dec 6 21:42 fonts
drwxr-xr-x 4 root root 4.0K Dec 6 16:13 styles
The question is thus how to integrate al these moving bits and pieces?
So far in fact TileServer starts, but with varying results:
- Sometimes it picks up the correct style location , but then crashes when accessing the styled data from the splash page
this is the error log:
ERROR: Font not found: Metropolis Light Italic
ERROR: Font not found: Metropolis Light Italic
/usr/src/app/src/serve_rendered.js:161
var range = parts[3].split('.')[0];
^
TypeError: Cannot read property 'split' of undefined
at request (/usr/src/app/src/serve_rendered.js:161:33)
at Object.request (/usr/src/app/node_modules/@mapbox/mapbox-gl-native/platform/node/index.js:21:13)
Even more weirdly, pointing the browser directly to the stylised map works (i.e. to something like http://YOUR-URL:YOUR-PORT/styles/positron/#7/44.194/12.107)
While this can just be an app bug, it is fairly annoying.
- A worse problem is due to the misalignment between the folder locations on the host filesystem, and those in teh containers. If for some (yet to be understood) reason Tileserver doesn't pick up the correct styleing location, it produces an on-the-fly config, which styles the data using two default styles residing in the container path.
This is the output log:
Waiting 3 seconds for xvfb to start...
Starting tileserver-gl v2.3.0
No MBTiles specified, using italy.mbtiles
Automatically creating config file for italy.mbtiles
{
"options": {
"paths": {
"root": "/usr/src/app/node_modules/tileserver-gl-styles",
"fonts": "fonts",
"styles": "styles",
"mbtiles": "/data"
}
},
"styles": {
"klokantech-basic": {
"style": "klokantech-basic/style.json",
"tilejson": {
"bounds": [
6.5272658,
35.1889616,
18.8844746,
47.1921462
]
}
},
"osm-bright": {
"style": "osm-bright/style.json",
"tilejson": {
"bounds": [
6.5272658,
35.1889616,
18.8844746,
47.1921462
]
}
}
},
"data": {
"v3": {
"mbtiles": "italy.mbtiles"
}
}
}
Starting server
Listening at http://[::]:80/
Startup complete
this is the command:
sudo docker run -it -v $(pwd)/data:/data -v $(pwd)/styles:/styles -v $(pwd)/fonts:/fonts -p 3001:80 klokantech/tileserver-gl -c config.json --verbose
NOTE there's now a different mapping regading the data location flag in Docker:
BEFORE | NOW |
---|---|
-v $(pwd):/data |
-v $(pwd)/data:/data |
This is the splash page (NOTE again the two different default styles, now available)
While in this configuration the app runs smoothly it - doens't pick up the correct style (although it recognizes the data location!) - doesn't return any other data apart from the one specfified for styling purposes. NOTE this is a crucial problem when trying to serve data no merely for styling (such as the case of background maps) but for data analysis (or any other purpose really).
Given the mismatch between the paths, the goal is thus to produce a functioning configuration, able to pick up all the components (style, data, fonts...) from the local folder to allow a truly customisable instance of tileserver.