rd13_tile_server/docs/adr/001-martin-tileserver-gl-stack.md

6.1 KiB
Raw Permalink Blame History

ADR-001: Tile Rendering Stack Martin + tileserver-gl

Date: 2026-06-12
Status: Accepted

Context

The tile server must serve map tiles to three external systems:

  • MediaWiki (Kartographer extension) requires raster PNG tiles for client-side rendering
  • Home Assistant requires raster PNG tiles for map visualization
  • Nextcloud may require vector or raster tiles in future

Current state:

  • Martin tile server distributes vector tiles (PBF format) from osm.mbtiles
  • osm.mbtiles contains static OSM snapshot (not live-updated data)
  • No client-side rendering capability for Kartographer (requires PNG or pre-rendered output)
  • Map rendering fails silently in MediaWiki without server-side PNG delivery

Key requirements:

  • Maps must display in MediaWiki without external tile server dependency
  • Styles and layer definitions must be customizable by team
  • Map tile updates are planned 24 times per year (not live)
  • Low operational overhead (single-server, docker-compose deployment)
  • Horizontal scaling is not a near-term requirement

Decision

Adopt a two-tier tile architecture:

  1. Martin (stays)

    • Role: Vector tile distribution API
    • Input: osm.mbtiles (static snapshot, updated manually 24×/year)
    • Output: PBF tiles via REST API (/{layer}/{z}/{x}/{y}.pbf)
    • Purpose: Foundation for future MapLibre GL integration, internal vector APIs
  2. tileserver-gl (new)

    • Role: PNG raster tile renderer + server
    • Input: Vector tiles from Martin + Style definitions (stored in /data/styles/)
    • Output: Raster PNG tiles via REST API (/{style}/{z}/{x}/{y}.png)
    • Purpose: Serve Kartographer and other raster-only clients

URL routing in Reverse Proxy (NPM):

  • /osm/{z}/{x}/{y}.pbf → Martin (internal/API use)
  • /osm-intl/{z}/{x}/{y}.png → tileserver-gl (Kartographer)
  • /osm-intl/{z}/{x}/{y}@2x.png → tileserver-gl (retina displays)

MediaWiki Config:

  • $wgKartographerMapServer = 'https://tiles.rd13server.de'
  • $wgKartographerDfltStyle = 'osm-intl' (raster style)
  • No external tile dependency

Consequences

Benefits

  • Minimal operational complexity Both Martin and tileserver-gl fit in docker-compose, combined ~200MB RAM
  • No external dependencies Kartographer renders entirely from local server; no upstream tile requests
  • Style customization tileserver-gl uses standard MapLibre GL styles (JSON); team can adjust colors, fonts, layer visibility without code changes
  • Flexible upgrade path If live OSM updates become required (2027+), OpenMapTiles Server can be added without disrupting Martin or tileserver-gl
  • Fast iteration Update cycle: download new osm.mbtiles → docker-compose restart → ~30 seconds downtime
  • Vector + Raster simultaneously Future clients (MapLibre GL, Leaflet vector) can coexist with raster-only systems (Kartographer)

Drawbacks

  • ⚠️ Manual tile refresh cycle No live OSM updates; requires download and swap of osm.mbtiles
  • ⚠️ PNG caching complexity Raster tiles are pre-rendered, so cached images may lag behind style changes by one tile-generation cycle
  • ⚠️ CPU spike during rendering tileserver-gl pre-warms cache on startup; brief CPU spike when new zoom level/area is requested for first time
  • ⚠️ Storage Raster caching will eventually consume disk space (~1GB per zoom level for Europe at full coverage); mitigation: define tile cache TTL

Alternatives Considered

Alternative A: OpenMapTiles Server (full-stack replacement)

Pros:

  • Live OSM data import pipeline
  • Central rendering engine with parametrized styling
  • Full control over data freshness

Cons:

  • Overengineered for current needs Requires PostGIS, Lua, full data pipeline; 35 GB footprint
  • High setup cost 35 days to operationalize + ongoing maintenance burden
  • Not needed yet static 24×/year updates don't justify infrastructure investment
  • Risk Complex system = more failure modes; Martin is proven production-grade today

Why not chosen: Defers to future decision (ADR-002?) when live update requirement becomes real.

Alternative B: External tile server proxy (OSM.org, Mapbox)

Pros:

  • Zero infrastructure investment
  • Instant map display

Cons:

  • Violates ToS OSM.org tile server prohibits automated/bulk access (Kartographer = repeated requests)
  • No resilience Dependent on external uptime; tiles fail if upstream is down
  • Violates NFR-001 REQ-001 requires "maps must be independently hostable"

Why not chosen: Does not meet architectural requirements.

Alternative C: Martin + client-side rendering (MapLibre GL only)

Pros:

  • Simpler stack (one service)
  • Full styling flexibility at runtime

Cons:

  • Breaks MediaWiki Kartographer does not support MapLibre GL client-side rendering
  • Blocks requirement MediaWiki maps would remain broken; unacceptable to stakeholders

Why not chosen: Fails functional requirements.

Implementation Plan

  1. Week 1

    • Add tileserver-gl to docker-compose.yml
    • Mount /data/styles/ and /data/fonts/ for style/font config
    • Create baseline osm-intl style (JSON) for raster rendering
    • Configure Nginx reverse proxy routing in NPM
  2. Week 2

    • Test end-to-end: MediaWiki mapframe → PNG delivery
    • Verify cache headers and CDN-friendliness
    • Document in ADMIN.md: tile update workflow
  3. Week 3

    • Performance testing (p95 response times, cache hit rates)
    • Rollback procedure documentation
    • Team training on style customization

Future Decisions

  • ADR-002: Live OSM update pipeline (if 2027 requirement arises)
  • ADR-003: Horizontal tile server scaling (if traffic exceeds single-server capacity)
  • ADR-004: Sprites and fonts CDN distribution

References