Documentation

Get tileserver-rs running with real map data in just a few minutes.

Prerequisites

Step 1: Download Sample Data

We'll use a sample PMTiles file containing OpenStreetMap data for Florence, Italy:

mkdir -p data/tiles
curl -L -o data/tiles/florence.pmtiles \
  https://github.com/vinayakkulkarni/tileserver-rs/raw/main/data/tiles/protomaps-sample.pmtiles

Step 2: Start the Server

You can start the server with zero config (auto-detect) or with an explicit config file:

Zero-Config (auto-detect)
# Point at the data directory — sources, styles, and fonts are auto-detected
tileserver-rs data/
With Config File
# Create a config.toml first
cat > config.toml << 'EOF'
[[sources]]
id = "florence"
type = "pmtiles"
path = "data/tiles/florence.pmtiles"
name = "Florence"
attribution = "© OpenStreetMap contributors"
EOF

tileserver-rs --config config.toml
Docker
docker run -p 8080:8080 \
  -v $(pwd)/data:/data:ro \
  ghcr.io/vinayakkulkarni/tileserver-rs:latest /data

You should see:

INFO tileserver_rs: Auto-detected from: /path/to/data
INFO tileserver_rs:   Sources: 1 (florence)
INFO tileserver_rs: Starting tileserver on http://0.0.0.0:8080
Info

Zero-config auto-detect finds .pmtiles, .mbtiles, style.json, fonts, and GeoJSON files. See the Auto-Detect Guide for details.

Step 4: Explore Your Tiles

Open your browser to http://localhost:8080 to see the built-in map viewer.

Available Endpoints

EndpointDescription
localhost:8080Web UI with map viewer
localhost:8080/data.jsonList all tile sources
localhost:8080/data/florence.jsonTileJSON metadata
localhost:8080/healthHealth check
localhost:8080/pingRuntime metadata (config hash, version)

Fetch a Tile

# Get a vector tile (zoom 14, Florence city center)
curl -I http://localhost:8080/data/florence/14/8704/5972.pbf

# Response:
# HTTP/1.1 200 OK
# content-type: application/x-protobuf
# content-encoding: gzip

Step 5: Display in MapLibre GL JS

Create an index.html file:

<!DOCTYPE html>
<html>
  <head>
    <title>My First Tile Server</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      href="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.css"
      rel="stylesheet"
    />
    <script src="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.js"></script>
    <style>
      body {
        margin: 0;
        padding: 0;
      }
      #map {
        position: absolute;
        top: 0;
        bottom: 0;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      const map = new maplibregl.Map({
        container: 'map',
        style: {
          version: 8,
          sources: {
            florence: {
              type: 'vector',
              url: 'http://localhost:8080/data/florence.json',
            },
          },
          layers: [
            {
              id: 'water',
              type: 'fill',
              source: 'florence',
              'source-layer': 'water',
              paint: { 'fill-color': '#a0cfdf' },
            },
            {
              id: 'roads',
              type: 'line',
              source: 'florence',
              'source-layer': 'transportation',
              paint: { 'line-color': '#888', 'line-width': 1 },
            },
            {
              id: 'buildings',
              type: 'fill',
              source: 'florence',
              'source-layer': 'building',
              paint: { 'fill-color': '#d9c9b9', 'fill-opacity': 0.7 },
            },
          ],
        },
        center: [11.255, 43.77], // Florence, Italy
        zoom: 14,
      });
    </script>
  </body>
</html>

Open index.html in your browser to see the map!

What's Next?

Common Issues

Port Already in Use

# Use a different port
docker run -p 3000:8080 ...

# Or with local binary
tileserver-rs --config config.toml --port 3000

Permission Denied (Docker)

Make sure your data directory is readable:

chmod -R 755 data/

Tiles Return 404

Check that your source ID matches the URL path:

  • Config: id = "florence"
  • URL: /data/florence/{z}/{x}/{y}.pbf