Sign inSign up

stsdockerhub/tileserver-gl

By stsdockerhub

•Updated 11 days ago

Self-hosted OpenStreetMap vector tile server (tileserver-gl fork) with stateless S3/PMTiles images

Image
Developer tools
Web servers
0

999

stsdockerhub/tileserver-gl repository overview

⁠TileServer GL — self-hosted OpenStreetMap tiles

Vector map tile server with GL styles, built from a vendored and extended fork of maptiler/tileserver-gl⁠ (based on upstream 5.7.0-pre.1). Serves OpenMapTiles⁠-schema MBTiles/PMTiles, for example generated from OpenStreetMap / Geofabrik extracts with Planetiler⁠, to MapLibre GL JS, Android/iOS, Leaflet and OpenLayers clients.

Source, docs, changelog and dev stack: https://github.com/tgivslife/openstreetmap-tileserver-gl⁠


⁠Tags

Current version: 1.0.0 · platforms linux/amd64 and linux/arm64 (one tag, the right architecture is pulled automatically).

TagDockerfileWhat it is
1.0.0-lightDockerfile_lightVector only. Vector tiles, styles, fonts, sprites and TileJSON. No GL stack, small image.
1.0.0-light-s3Dockerfile_light_s3The same light image with a config.json, styles and fonts baked in. A stateless container that reads PMTiles from S3-compatible object storage; retarget it with environment variables, no rebuild needed.
  • Versioning: the fork has its own semver⁠; each release's notes, and the upstream tileserver-gl version it is based on, are in the CHANGELOG⁠. There is no latest tag: pin a version.
  • Per-architecture tags (1.0.0-light-amd64, 1.0.0-light-arm64, …) are build intermediates; use the plain tags.
  • Provenance: every image is labelled with its version, git commit, build date and upstream base: docker inspect -f '{{json .Config.Labels}}' stsdockerhub/tileserver-gl:1.0.0-light-s3
  • Full image (server-side raster rendering, static maps, WMTS, elevation) is not published; build it from source with npm run images:build -- full.

⁠What's added on top of upstream

  • S3 / object storage data sources. PMTiles from s3:// (AWS), s3+https:// / s3+http:// (MinIO, Ceph, R2, …) or plain https:// range reads. Private buckets use the standard AWS credential chain (env vars, mounted ~/.aws profile, IAM role); credentials are never read from config.json. Each range read has a deadline, so a stalled store fails fast with a 504 instead of hanging requests.
  • Storage failures are answered as errors, not empty tiles: 502/503/504 with Cache-Control: no-store, so a CDN never caches an outage as blank map.
  • ${VAR} / ${VAR:-default} substitution in any config.json string, so one baked config works across deployments; a required variable that is unset stops startup by name.
  • API keys and expiring HMAC tokens (?key=), propagated into every generated URL, plus an optional Origin/Referer allowlist for hotlink deterrence. Keys are redacted from the request log, and responses under a token are never cacheable beyond its expiry.
  • CDN-friendly Cache-Control on every successful response, configurable per category, with correct ETag/304 revalidation.
  • Prometheus metrics on a separate loopback-bound port.
  • /health endpoint used by the built-in Docker HEALTHCHECK; stays open when auth is enabled.
  • Config reload on SIGHUP without restarting the container; requests during the reload get a retryable 503 Starting, never a 404.
  • Light/dark theme toggle in the style viewer for any style that has a -dark sibling.

⁠Quick start

⁠Serve a local MBTiles file (light image)
# Generate tiles first, e.g. with Planetiler:
docker run -e JAVA_TOOL_OPTIONS="-Xmx1g" -v "$(pwd)/data":/data \
  ghcr.io/onthegomap/planetiler:latest --download --area=monaco

docker run --rm -it -v "$(pwd)/data":/data -p 8080:8080 \
  stsdockerhub/tileserver-gl:1.0.0-light

Open http://localhost:8080/⁠. With no config.json in /data, the server picks up the first *.mbtiles / *.pmtiles file it finds and, for OpenMapTiles-format data, serves the bundled styles against it.

⁠Stateless S3 deployment
docker run --rm -it -p 8080:8080 \
  -e PMTILES_URL="s3+https://minio.example.com/tiles/planet.pmtiles" \
  -e AWS_ACCESS_KEY_ID=... \
  -e AWS_SECRET_ACCESS_KEY=... \
  stsdockerhub/tileserver-gl:1.0.0-light-s3

A complete MinIO example (private bucket, SigV4) is in tileserver-gl-dev/compose.s3.yml⁠.

Remap the port with -p (or set PORT), not with --port: the built-in healthcheck probes $PORT (default 8080) inside the container, so a --port change makes the container report unhealthy.

⁠Bundled styles (-light-s3)

osm-openmaptiles, streets-v2, basic-v2 and streets-v2-survey (survey-optimised streets), each with a -dark variant and its own sprite sheet, localized to be served entirely by this server (no external API key). Includes 14 glyph sets (Noto Sans, Open Sans and variants).

⁠Environment variables

All optional, except PMTILES_URL for -light-s3.

GroupVariables
ServerPORT, BIND, PUBLIC_URL, NODE_ENV, UV_THREADPOOL_SIZE
Auth / securityTILESERVER_GL_API_KEYS, TILESERVER_GL_TOKEN_SECRET, TILESERVER_GL_TOKEN_MAX_TTL, TILESERVER_GL_ALLOWED_ORIGINS, TILESERVER_GL_ALLOWED_HOSTS
MetricsTILESERVER_GL_METRICS, TILESERVER_GL_METRICS_ZOOM, METRICS_PORT
S3 credentialsAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_REGION, AWS_PROFILE
S3 client tuningTILESERVER_GL_S3_MAX_SOCKETS, TILESERVER_GL_S3_KEEP_ALIVE, TILESERVER_GL_S3_CONNECTION_TIMEOUT_MS, TILESERVER_GL_S3_REQUEST_TIMEOUT_MS
Baked S3 config (-light-s3)PMTILES_URL (tileset location, required), TILE_CACHE_CONTROL (tile Cache-Control)

Full descriptions: USAGE.md › Environment variables⁠.

⁠Ports and endpoints

PortPurpose
8080HTTP: tiles, styles, fonts, sprites, TileJSON, viewers, /health
9090Prometheus /metrics (when enabled; bound to 127.0.0.1 inside the container)

Key endpoints: /styles/{id}/style.json, /data/{id}/{z}/{x}/{y}.pbf, /fonts/{fontstack}/{range}.pbf, /styles/{id}/ (viewer), /health.

⁠Performance

-light-s3 reading from MinIO over S3 (Romania tileset, z8–14, k6, 0 errors):

SetupThroughputVector-tile p95
1 container, 50 users~640–1,270 req/s depending on the host354–632 ms
1 container, fixed arrival rate (Apple M1 Max)holds p95 < 200 ms up to ~740 req/s< 200 ms
4 replicas + LB, 200 users (32-core host)~1,275 req/s745 ms

Containers are stateless and degrade by adding latency, not errors. Scale out horizontally and put a CDN in front; the cache headers are already set for it. Method and full tables: k6 README⁠.

⁠Operations

docker kill -s HUP <container>   # reload config.json without a restart

⁠Documentation

Install⁠ · Usage & endpoints⁠ · Configuration⁠ · Deployment⁠ · Changelog⁠

⁠Credits

Based on TileServer GL⁠ by MapTiler and the OpenMapTiles⁠ schema. Map data © OpenStreetMap⁠ contributors (ODbL). Styles derived from MapTiler / OpenMapTiles styles. Keep the required attributions visible on any map you publish.

Tag summary

Content type

Image

Digest

sha256:829c2798b…

Size

176.3 MB

Last updated

11 days ago

docker pull stsdockerhub/tileserver-gl:1.0.2-light-s3