TileServer GL
TileServer GL handles vector and raster maps as a self-hosted solution.
Open-source map tile server, honestly reviewed. No marketing fluff, just what you get when you run your own tile infrastructure.
TL;DR
- What it is: An open-source map tile server that serves vector and raster map tiles from your own infrastructure — think “Mapbox, but the server runs in your data center” [1].
- Who it’s for: Developers and technical founders running apps with maps who are tired of Mapbox or Google Maps Platform billing that scales with traffic. Also GIS teams who need WMTS compatibility for enterprise GIS software [1][2].
- Cost savings: Mapbox charges per map load — $0.50 per 1,000 loads after the free tier, which means a moderately trafficked app hits $500–$5,000/month fast. TileServer GL on a $10/mo VPS with self-hosted OpenMapTiles data is a fixed cost [1].
- Key strength: Handles both vector and raster tiles from a single server, with server-side rendering via MapLibre GL Native. That means clients that can’t render vector tiles (older Leaflet setups, GIS software, static image consumers) still get proper map images [1][2].
- Key weakness: This is not a tool for non-technical founders. It requires understanding tile formats (MBTiles, PMTiles), GL styles, and enough ops knowledge to run a Docker container or Node.js process. There’s no admin UI — configuration is JSON files [2].
What is TileServer GL
TileServer GL is a Node.js application that turns local map data files into a live tile API. You point it at an MBTiles file (a SQLite database containing map tiles), give it a GL style JSON, and it starts serving:
- Vector tiles — raw geographic data that the client renders using GL styles
- Raster tiles — pre-rendered PNG images generated server-side by MapLibre GL Native
- WMTS endpoints — for GIS software like QGIS, ArcGIS, MapInfo
- Static image exports — PNG renders of specific map views
- TileJSON — the metadata endpoint that MapLibre GL JS and other clients consume to discover your tile source [1][2]
The project is maintained by MapTiler, a Swiss geodata company that also sells a commercial cloud tile service. The self-hosted version lives at https://github.com/maptiler/tileserver-gl with 2,757 GitHub stars [1].
The split between two packages matters:
tileserver-gl— the full version. Uses MapLibre GL Native (a C++ rendering library) to rasterize vector tiles server-side. Requires native build dependencies. Ships as a Docker image to sidestep this.tileserver-gl-light— pure JavaScript, no native dependencies, runs anywhere Node runs. Does not do server-side rasterization — it only serves vector tiles and relies on the client to render them [1].
For most use cases, you want the full version via Docker. The light version exists if you need to run on platforms that can’t install native libraries, but you lose raster tile output.
The map data itself doesn’t come bundled. The most common source is OpenMapTiles — a global planet dataset that MapTiler makes available for download. You pair TileServer GL (the server) with OpenMapTiles data (the tiles) and a GL style (the visual design), and you have a self-hosted map stack [1].
Why people choose it
Third-party reviews specific to TileServer GL were not available for this article. The analysis below comes from the primary documentation, README, and technical characteristics of the tool.
The decision to run TileServer GL almost always starts with a Mapbox bill. Mapbox pricing is load-based: once your free tier runs out, you pay per map view. An app with 1 million monthly map loads pays roughly $500/month. At 10 million loads, you’re looking at $4,500/month. The bill is invisible until it isn’t, and it scales with your success rather than your costs.
The alternative isn’t free — OpenMapTiles planet data downloads cost real money too (MapTiler charges for the full planet extract), and you need infrastructure to run TileServer GL. But the math shifts from “per request” to “fixed infrastructure,” which most engineering teams find easier to budget and reason about.
Versus Mapbox: Mapbox GL JS is the dominant web mapping library. If you’re already on the MapLibre GL JS fork (which is MIT-licensed and compatible), TileServer GL plugs in directly. You keep the same client-side code; you just change the tile source URL to point at your own server [1][2]. Mapbox wins on ease (no ops) and proprietary features like traffic data and geocoding. You give those up when you self-host.
Versus Google Maps Platform: Google charges per API call. Maps JavaScript API, Geocoding API, Places API — each is billed separately. For applications that just display a map without Google-specific features (search, directions), TileServer GL with OpenMapTiles is a complete replacement at a fraction of the cost. For applications that need Google’s POI data or geocoding accuracy, it’s not a drop-in.
Versus cloud tile services (MapTiler Cloud, Stadia Maps, Thunderforest): These are the middle option — someone else runs the tile server, but it’s not Mapbox. MapTiler Cloud’s free tier gives 100K requests/month. Paid plans are cheaper than Mapbox. TileServer GL makes sense over cloud tile services when you need data sovereignty (the map requests shouldn’t leave your network), air-gapped deployments, or truly unlimited tile serving without metered pricing [2].
Versus Tegola or Martin: These are newer, faster tile servers written in Go and Rust respectively. They serve vector tiles directly from PostGIS databases. TileServer GL is different: it serves from MBTiles files (pre-generated) and adds server-side rasterization that Tegola and Martin don’t do. If you have a PostGIS database and want dynamic tiles, Martin or Tegola are worth evaluating. If you have pre-packaged tile data files and need raster output or WMTS, TileServer GL is the better fit.
Features
Based on the README and documentation [1][2]:
Tile serving:
- Vector tile serving (MVT format) from MBTiles files [1]
- Raster tile rendering via MapLibre GL Native — turns vector tiles into PNG images on the server [1]
- Multiple data sources and styles served from one instance [2]
- WMTS endpoint for GIS software compatibility [2]
- TileJSON endpoint for client auto-discovery [2]
Configuration:
config.jsonfile defines styles, data sources, and serving options [2]- Hot reload support — the docs mention reloading config without restart [2]
- Remote tile source support (fetching tiles from external URLs with configurable timeouts) [2]
Static image export:
- Endpoint for rendering static PNG images of specific map views [2]
- Useful for generating map thumbnails, email maps, PDF reports without a browser
Font serving:
- Serves glyph fonts needed by GL styles for label rendering [2]
- Required when you’re using GL styles that include text labels on the map
Deployment options:
- Docker image:
maptiler/tileserver-gl:latest— the recommended production path [1] - npm global install:
npm install -g tileserver-gl— requires native dependencies pre-installed [1] - Light variant:
tileserver-gl-lightormaptiler/tileserver-gl-light— pure JS, no rasterization [1]
Production hardening:
--public_urlflag to set canonical URL and prevent host header poisoning [1]TILESERVER_GL_ALLOWED_HOSTSenvironment variable to whitelist accepted host headers [1]- Cloudflare and Nginx cache configuration documented [2]
- Nginx reverse proxy configuration included in docs [2]
What’s missing:
- No admin UI — everything is config files
- No authentication or API keys built in (you add that at the reverse proxy layer)
- No tile generation — you bring your own MBTiles data
- No geocoding, routing, or search — tile serving only
Pricing: SaaS vs self-hosted math
MapTiler Cloud (their own SaaS):
- Free tier: 100,000 API requests/month
- Flex: pay-as-you-go pricing kicks in after free tier
- Custom plans for high-volume users
Exact current pricing not available; check https://www.maptiler.com/cloud/pricing/ directly.
Mapbox for comparison (the pain point TileServer GL addresses):
- Maps JS API: $0.50 per 1,000 loads after free tier (50,000 loads/month free)
- At 100K loads/month: ~$25/month
- At 1M loads/month: ~$450/month
- At 10M loads/month: ~$4,250/month
TileServer GL self-hosted:
- Software: free (open-source) [1]
- Data: OpenMapTiles planet extract — pricing varies; regional extracts from MapTiler start lower
- Infrastructure: $10–30/month VPS depending on your tile serving volume and whether you need raster rendering (CPU-intensive)
- Bandwidth: counts against your VPS or CDN bill — tile payloads are small but volume adds up at scale
Concrete math for a mid-sized app:
An app serving 5 million map loads per month on Mapbox pays roughly $2,225/month. On TileServer GL with a dedicated $40/month server and a CDN in front of it, your monthly spend might be $60–100/month. That’s roughly $25,000/year saved, at the cost of operational overhead.
The math breaks down at very low traffic (Mapbox free tier covers 50K loads/month; TileServer GL setup cost isn’t worth it for casual apps) and at very high traffic (Mapbox’s negotiated enterprise deals may close the gap; your ops team also has a cost).
Deployment reality check
The Docker path is well-documented and genuinely straightforward for anyone comfortable with Docker [1]:
docker run --rm -it -v $(pwd):/data -p 8080:8080 \
maptiler/tileserver-gl:latest --file your.mbtiles
That’s a working tile server in one command once you have an MBTiles file. The default UI at port 8080 shows a preview of your tiles.
What you actually need for production:
- Linux VPS or container host — 2+ CPU cores for raster rendering (MapLibre GL Native is CPU-intensive)
- 2–4GB RAM minimum; more if serving large planet extracts
- Storage for tile data — a full planet MBTiles file is 60–100GB
- A reverse proxy (Nginx or Caddy) for HTTPS and caching
- An MBTiles file — either downloaded from MapTiler or generated with tools like
tippecanoe - GL styles — either open styles (MapTiler’s free styles, OpenMapTiles styles) or custom ones
What can go sideways:
- The native dependency requirement for the non-Docker npm install is the most common pain point. The docs link out to platform-specific dependency installation, but it’s non-trivial on fresh Linux systems. Docker sidesteps this entirely [1].
- Server-side rasterization is CPU-heavy. If you’re generating raster tiles on-demand (rather than caching them), a single-core VPS will struggle under load.
- No built-in auth. If your tile server should be private, you implement that at the Nginx layer. Easy if you know how; a gotcha if you assume the server handles it.
- The host header poisoning vulnerability is real and documented [1]. Set
--public_urlin production — one flag, but you have to know about it. - WMTS configuration for GIS software requires understanding the endpoint format. The docs cover it, but GIS clients have their own quirks [2].
Production-ready checklist:
- Set
--public_urlto prevent HNP attacks [1] - Put Nginx or Cloudflare in front for caching and TLS [2]
- Configure
TILESERVER_GL_ALLOWED_HOSTSif not using--public_url[1] - Mount tile data as a volume, not baked into the image [1]
- Set up health check endpoint (
/health) for container orchestration [2]
Realistic time for a developer: 2–4 hours from zero to a working, HTTPS-enabled tile server. The tile data acquisition takes longer than the server setup.
Pros and Cons
Pros
- Docker-first deployment. The Docker path is clean and avoids the native dependency complexity. One command, working server [1].
- Server-side raster rendering. Most self-hosted tile servers only serve vector tiles. TileServer GL’s MapLibre GL Native integration means clients that can’t render GL (older Leaflet, GIS software, static image generators) get proper raster tiles [1].
- WMTS support. Genuine GIS software compatibility. If your use case involves QGIS, ArcGIS, or MapInfo consuming your tile server, this matters [2].
- Static image export. Handy for generating map PNGs without a headless browser.
- MapTiler backing. Not a side project — maintained by the company that sells commercial map services. Aligned incentives to keep the open-source version working [1].
- Light variant available. If you only need vector tiles and can’t install native deps,
tileserver-gl-lightruns anywhere Node runs [1]. - Well-documented security guidance. The host header poisoning documentation and mitigation options are clearly written in the README [1].
Cons
- No admin UI. Everything is JSON configuration. You edit files, restart the server, check the preview. Fine for developers, bad for non-technical operators [2].
- No auth built in. Access control is entirely your responsibility at the proxy layer.
- CPU-intensive raster rendering. Serving raster tiles under load requires real CPU. Under-provision the server and your tile rendering will be slow or will fail.
- Tile data not included. You have to source your own MBTiles. The full planet dataset from MapTiler costs money. Free regional extracts exist for testing.
- License marked NOASSERTION. The merged profile shows the license wasn’t cleanly identified. The repository itself uses BSD-2-Clause for the server code, but the exact terms around bundled MapLibre GL Native binaries warrant review before commercial use [1].
- No dynamic tile generation from PostGIS. If your geodata lives in a database rather than a file, you need a different tool (Martin, Tegola) or a pre-generation pipeline.
- 2,757 GitHub stars. Respectable but not dominant. Smaller community than Mapbox or the PostGIS-native alternatives.
Who should use this / who shouldn’t
Use TileServer GL if:
- You have a web or mobile app serving maps that’s paying Mapbox or Google Maps at scale and the bill hurts.
- You need WMTS endpoints for GIS software — this is one of the few self-hosted options that handles it.
- You need server-side raster tile generation (for non-GL clients or static image exports).
- You’re comfortable with Docker and basic Nginx configuration.
- Your data requirements are satisfied by OpenMapTiles-format data (OSM-based global maps, custom vector data converted to MBTiles).
- You need an air-gapped or private network map stack where tile requests can’t go to external services.
Skip it (pick Martin or Tegola) if:
- Your geodata lives in PostGIS and you want dynamic tiles from live database queries.
- You only need vector tiles and don’t need server-side rasterization or WMTS.
- You want a faster, lower-memory Rust or Go binary instead of Node.js.
Skip it (stay on MapTiler Cloud or Stadia Maps) if:
- You’re under 100K map loads/month — managed cloud tile services are free or cheap at that scale.
- You don’t have anyone who can manage a Docker container and configure Nginx.
- You need geocoding, routing, or search alongside your tiles — tile servers don’t do any of that.
Skip it entirely if:
- You’re a non-technical founder who just needs a map on your website. Use a managed service. The operational complexity of self-hosted tile serving isn’t worth it below a certain traffic threshold.
Alternatives worth considering
- Martin — Rust-based tile server, serves vector tiles directly from PostGIS. Faster and lower memory than TileServer GL. No raster rendering, no WMTS. Good if your data is in Postgres.
- Tegola — Go-based, also PostGIS-native. Similar trade-offs to Martin.
- pg_tileserv / TiPg — Minimal PostGIS tile servers. Very lightweight, no configuration overhead, but bare-bones feature set.
- MapTiler Cloud — MapTiler’s own managed service. 100K requests/month free. If you want someone else to run TileServer GL’s technology, this is effectively that.
- Stadia Maps — Third-party cloud tile service, cheaper than Mapbox, not self-hosted.
- Mapbox — The incumbent. Best tooling, most integrations, most expensive at scale, fully closed.
- OpenLayers / Leaflet with external tile sources — Not a tile server, but worth noting: if you only need a map widget, there are free public tile sources (OpenStreetMap’s tile layer for non-commercial use) that don’t require running any server.
Bottom line
TileServer GL solves one problem well: serving map tiles from your own infrastructure. If you have a real Mapbox or Google Maps bill and your geodata fits the MBTiles/OpenMapTiles model, the economics are compelling — fixed infrastructure cost versus a per-request bill that only climbs. The Docker deployment path is clean, the WMTS support is a genuine differentiator for GIS use cases, and the server-side raster rendering covers client types that vector-only servers can’t handle.
The honest caveat is that this is a developer tool, not a product. There’s no admin UI, no built-in auth, no tile generation — you’re assembling a stack, not installing an application. Non-technical founders won’t self-install this. If the Mapbox bill hurts but you don’t have a developer on staff, that’s what unsubbed.co’s parent studio upready.dev deploys for clients — your tile infrastructure, set up once, fixed monthly cost, you own it.
Sources
- TileServer GL GitHub Repository — README, installation instructions, security documentation. https://github.com/maptiler/tileserver-gl (2,757 stars, MapTiler)
- TileServer GL Official Documentation — Usage, configuration, endpoints, deployment guides. https://tileserver.readthedocs.io/en/latest/
- Docker Hub — maptiler/tileserver-gl — Docker image and usage. https://hub.docker.com/r/maptiler/tileserver-gl/
Features
Mobile & Desktop
- Mobile App
Category
Related Maps & Geolocation Tools
View all 30 →Organic Maps
13KOrganic Maps is a self-hosted privacy & encryption tool with support for privacy, android, ios.
Dawarich
8.4KDawarich gives you visualize your location history on your own infrastructure.
Open Source Routing Machine (OSRM)
7.6KReleased under BSD-2-Clause, Open Source Routing Machine (OSRM) provides high performance routing engine designed to run on OpenStreetMap data and offering...
GraphHopper
6.4KFor maps & geolocation, GraphHopper is a self-hosted solution that provides fast routing library and server using OpenStreetMap.
evcc
6.3KEvcc handles extensible Electric Vehicle Charge Controller and home energy management system as a self-hosted solution.
Nominatim
4.2KNominatim is a self-hosted maps & geolocation tool that provides server application for geocoding (address -> coordinates) and reverse geocoding...