Guides

Docker Deployment

Deploy tileserver-rs with Docker and Docker Compose

This guide covers running tileserver-rs in Docker containers for development and production deployments.

Quick Start

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

Docker Images

Official images are published to GitHub Container Registry:

TagDescription
latestLatest stable release
vX.Y.ZSpecific version (e.g., v0.2.1)
mainLatest build from main branch
# Pull latest stable
docker pull ghcr.io/vinayakkulkarni/tileserver-rs:latest

# Pull specific version
docker pull ghcr.io/vinayakkulkarni/tileserver-rs:v0.2.1

Basic Usage

Directory Structure

my-tileserver/
├── config.toml
├── data/
│   ├── tiles/
│   │   └── world.pmtiles
│   ├── styles/
│   │   └── bright/
│   │       ├── style.json
│   │       ├── sprite.json
│   │       └── sprite.png
│   └── fonts/
│       └── Noto Sans Regular/
│           ├── 0-255.pbf
│           └── ...
└── compose.yml

Configuration File

# config.toml
fonts = "/data/fonts"

[server]
host = "0.0.0.0"
port = 8080

[[sources]]
id = "world"
type = "pmtiles"
path = "/data/tiles/world.pmtiles"
name = "World Map"

[[styles]]
id = "bright"
path = "/data/styles/bright/style.json"

Run with Docker

docker run -d \
  --name tileserver \
  -p 8080:8080 \
  -v $(pwd)/data:/data:ro \
  -v $(pwd)/config.toml:/app/config.toml:ro \
  -e RUST_LOG=info \
  ghcr.io/vinayakkulkarni/tileserver-rs:latest

Docker Compose

Development Setup

# compose.yml
services:
  tileserver:
    image: ghcr.io/vinayakkulkarni/tileserver-rs:latest
    ports:
      - "8080:8080"
    volumes:
      - ./data:/data:ro
      - ./config.toml:/app/config.toml:ro
    environment:
      - RUST_LOG=debug
    restart: unless-stopped
docker compose up -d
docker compose logs -f

Production Setup

# compose.prod.yml
services:
  tileserver:
    image: ghcr.io/vinayakkulkarni/tileserver-rs:latest
    ports:
      - "8080:8080"
    volumes:
      - ./data:/data:ro
      - ./config.toml:/app/config.toml:ro
    environment:
      - RUST_LOG=info
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 256M
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
docker compose -f compose.prod.yml up -d

With Reverse Proxy (Traefik)

# compose.yml
services:
  tileserver:
    image: ghcr.io/vinayakkulkarni/tileserver-rs:latest
    volumes:
      - ./data:/data:ro
      - ./config.toml:/app/config.toml:ro
    environment:
      - RUST_LOG=info
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.tiles.rule=Host(`tiles.example.com`)"
      - "traefik.http.routers.tiles.tls=true"
      - "traefik.http.routers.tiles.tls.certresolver=letsencrypt"
      - "traefik.http.services.tiles.loadbalancer.server.port=8080"
    networks:
      - traefik

  traefik:
    image: traefik:v3.0
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik:/etc/traefik
    networks:
      - traefik

networks:
  traefik:
    external: true

With nginx Reverse Proxy

# compose.yml
services:
  tileserver:
    image: ghcr.io/vinayakkulkarni/tileserver-rs:latest
    volumes:
      - ./data:/data:ro
      - ./config.toml:/app/config.toml:ro
    environment:
      - RUST_LOG=info

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - tileserver
# nginx.conf
events {
    worker_connections 1024;
}

http {
    proxy_cache_path /tmp/tiles levels=1:2 keys_zone=tiles:10m max_size=1g inactive=7d;

    upstream tileserver {
        server tileserver:8080;
        keepalive 32;
    }

    server {
        listen 80;
        server_name tiles.example.com;

        # Vector tiles - cache for 7 days
        location ~ ^/data/.*\.(pbf|mvt)$ {
            proxy_pass http://tileserver;
            proxy_cache tiles;
            proxy_cache_valid 200 7d;
            proxy_cache_valid 204 1h;
            add_header X-Cache-Status $upstream_cache_status;
        }

        # Static images - cache for 1 hour
        location ~ ^/styles/.*/static/ {
            proxy_pass http://tileserver;
            proxy_cache tiles;
            proxy_cache_valid 200 1h;
        }

        # Everything else
        location / {
            proxy_pass http://tileserver;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

Building Custom Images

Build from Source

# Clone repository
git clone https://github.com/vinayakkulkarni/tileserver-rs.git
cd tileserver-rs

# Build for your platform
docker build -t tileserver-rs:local .

# Build with specific target
docker build --platform linux/amd64 -t tileserver-rs:amd64 .
docker build --platform linux/arm64 -t tileserver-rs:arm64 .

Multi-Platform Build

# Create builder
docker buildx create --name multiplatform --use

# Build for multiple platforms
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t myregistry/tileserver-rs:latest \
  --push .

Custom Dockerfile

# Dockerfile.custom
FROM ghcr.io/vinayakkulkarni/tileserver-rs:latest

# Add your tiles and config
COPY data/ /data/
COPY config.toml /app/config.toml

# Set environment
ENV RUST_LOG=info
docker build -f Dockerfile.custom -t my-tileserver:latest .
docker run -p 8080:8080 my-tileserver:latest

Environment Variables

VariableDescriptionDefault
RUST_LOGLog level (error, warn, info, debug, trace)info
CONFIG_PATHPath to config file inside container/app/config.toml
environment:
  - RUST_LOG=debug  # More verbose logging
  - RUST_LOG=tileserver_rs=debug,tower_http=info  # Selective logging

Volume Mounts

Host PathContainer PathDescription
./data/dataTile files, styles, fonts
./config.toml/app/config.tomlConfiguration file
Always mount data directories as read-only (:ro) in production to prevent accidental modifications.

Health Checks

The /health endpoint returns OK when the server is ready:

# Check health
curl http://localhost:8080/health

# Docker health check
docker inspect --format='{{.State.Health.Status}}' tileserver

Resource Limits

Memory

tileserver-rs is memory-efficient, but large tile files may need more memory:

Tile File SizeRecommended Memory
< 1 GB256 MB
1-10 GB512 MB - 1 GB
> 10 GB2 GB+

CPU

For high-throughput scenarios:

Use CaseRecommended CPUs
Development0.5
Light production1
High traffic2-4
Static image rendering4+

Scaling

Horizontal Scaling

Run multiple instances behind a load balancer:

# compose.yml
services:
  tileserver:
    image: ghcr.io/vinayakkulkarni/tileserver-rs:latest
    volumes:
      - ./data:/data:ro
      - ./config.toml:/app/config.toml:ro
    deploy:
      replicas: 3

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    depends_on:
      - tileserver

Docker Swarm

# Initialize swarm
docker swarm init

# Deploy stack
docker stack deploy -c compose.prod.yml tileserver

# Scale
docker service scale tileserver_tileserver=5

Logging

View Logs

# Follow logs
docker compose logs -f tileserver

# Last 100 lines
docker compose logs --tail 100 tileserver

# Filter by time
docker compose logs --since 1h tileserver

Log Levels

environment:
  # Minimal logging
  - RUST_LOG=warn
  
  # Standard logging
  - RUST_LOG=info
  
  # Debug logging
  - RUST_LOG=debug
  
  # Trace logging (very verbose)
  - RUST_LOG=trace
  
  # Component-specific
  - RUST_LOG=tileserver_rs::sources=debug,tileserver_rs::render=trace

Troubleshooting

Container Won't Start

# Check logs
docker logs tileserver

# Common issues:
# - Config file not found: Check volume mounts
# - Permission denied: Check file permissions
# - Port in use: Change port mapping

Performance Issues

# Check resource usage
docker stats tileserver

# Check container limits
docker inspect tileserver | jq '.[0].HostConfig.Memory'

File Not Found

# Verify mounts
docker exec tileserver ls -la /data
docker exec tileserver cat /app/config.toml

# Check paths in config match container paths

Next Steps