rd13_tile_server/docs/ADMIN.md
Conrad Schulz 9367ba5b6b
Some checks failed
Build & Push marker-api / build (push) Failing after 4s
fix: slim pin geometry, r/d=0.35 opening angle 20deg
Was: r=35.5% of size -> r/d=0.59 -> 36 deg opening -> fat oval
Now: r=24% of size -> r/d=0.35 -> 20 deg opening -> proper Google Maps pin shape
2026-07-01 12:23:31 +00:00

13 KiB
Raw Blame History

Administrator-Handbuch rd13_tile_server

Zielgruppe: Administratoren Menschen, die das System betreiben, deployen und konfigurieren. Voraussetzung: Grundkenntnisse in Linux, Docker und der eingesetzten Stack (Martin, tileserver-gl).


Systemvoraussetzungen

Komponente Mindestanforderung Empfohlen
OS Linux 5.10+ (oder macOS 12+) Ubuntu 22.04 LTS
RAM 1 GB 2-4 GB
Disk 5 GB (OS + Containers) 20 GB (mit Cache-Warmup)
Dependencies Docker 20.10+, docker-compose 2.0+ Docker Desktop / Compose v2
Network Port 9982 (Martin), Port 8080 (tileserver-gl) internal Public domain via NPM reverse proxy

Deployment

Erstes Aufsetzen

# Repository klonen
git clone ssh://git@192.168.178.6:2222/cschulz/rd13_tile_server.git /mnt/services-data/rd13_tile_server
cd /mnt/services-data/rd13_tile_server

# Daten-Verzeichnis initialisieren (falls nicht vorhanden)
mkdir -p data/{fonts,sprites,styles}

# Services starten
docker compose up -d

# Health-Checks verifizieren
docker compose ps
curl -s http://localhost:9982/health | jq .
curl -s http://localhost:8080/health

Updates einspielen (Tile-Daten)

Szenario: osm.mbtiles aktualisieren (24×/Jahr)

# 1. Neue MBTiles herunterladen (z.B. von OpenFreeMap)
cd /mnt/services-data/rd13_tile_server
python3 scripts/download-data.sh data/osm.mbtiles.new

# 2. Alte Datei backup-en
mv data/osm.mbtiles data/osm.mbtiles.$(date +%Y%m%d)

# 3. Neue Datei aktivieren
mv data/osm.mbtiles.new data/osm.mbtiles

# 4. Container neu starten (warm caches)
docker compose restart martin tileserver

# 5. Health-Check + Sampling testen
curl -s http://localhost:9982/osm | jq .
curl -s "http://localhost:9983/osm-intl/0/0/0.png" > /tmp/test.png && file /tmp/test.png

Höhere Zoom-Level bauen (auf Host-Rechner, nicht auf dem Server)

Planetiler läuft in einem eigenen Container auf dem Host-Rechner (MacBook, Desktop-PC etc.) mit genug RAM. Das Ergebnis wird per rsync auf den Server übertragen.

Europa z16 (empfohlen): ~280 GB Host-Disk, ~812h, 12 CPUs / 28 GB RAM

# Auf dem HOST-RECHNER ausführen (im geklonten Repo-Verzeichnis):

# Europa z0-16 (~80 GB Output, ~8-12h, ~280 GB Disk nötig)
AREA=europe MAX_ZOOM=16 RAM=28g BUILD_CPUS=12 BUILD_MEM=30g \
  docker compose -f docker-compose.build.yml up

# Germany z0-16 (kleiner Test: ~12 GB Output, ~2h, ~50 GB Disk)
AREA=germany MAX_ZOOM=16 RAM=8g \
  docker compose -f docker-compose.build.yml up

# Fertiges MBTiles auf Server übertragen (resume-fähig):
rsync -avh --progress --partial \
  ./build/output/europe.mbtiles \
  rd13server@192.168.178.6:/mnt/services-data/rd13_tile_server/data/osm-europe.mbtiles

# Martin auf dem Server neu starten:
ssh rd13server@192.168.178.6 \
  "cd /mnt/services-data/rd13_tile_server && docker compose restart martin"

# Neue Source prüfen:
curl https://tiles.rd13server.de/catalog | python3 -m json.tool | grep osm-europe

Build-Output liegt lokal unter ./build/output/<AREA>.mbtiles (gitignored). Sources-Cache unter ./build/sources/ bei Rebuild nicht löschen (spart Re-Download).

Planetiler Build-Steuerung (Cleanup/Resume)

Der Build trennt jetzt bewusst in kurzlebige und wiederverwendbare Daten:

  • build/output/ fertige MBTiles
  • build/sources/ Download-Cache (OSM + Zusatzdaten)
  • build/tmp/work/ laufzeitbezogene Temp-Daten (wegwerfbar)
  • build/tmp/reuse/ wiederverwendbare Feature-DB fuer --reuse_featuredb

Steuerung ueber Script:

# Status + Reuse-Readiness anzeigen
./scripts/planetiler-build-control.sh status

# Resume-Build: work leeren, reuse/sources behalten, dann starten
./scripts/planetiler-build-control.sh resume

# Fresh-Build: output+work+reuse leeren, sources behalten, dann starten
./scripts/planetiler-build-control.sh fresh

# Vollstaendig neu: output+sources+work+reuse leeren, dann starten
./scripts/planetiler-build-control.sh fresh-all

Hinweis: reuse ist nur aktiv, wenn diese Artefakte existieren:

  • build/tmp/reuse/feature.db/
  • build/tmp/reuse/feature.db/feature.db.strings
  • build/tmp/reuse/feature.db/feature.db.manifest

Satellit-Tiles herunterladen (einmalig, ~38 GB, ~24h)

Der Download läuft in einem eigenen Container vollständig unabhängig von SSH-Sessions und VS Code. Resume-fähig: bei Unterbrechung einfach neu starten.

Ressourcen: 16 Threads, 1 GB RAM-Limit (~40 MB effektiv), 4 CPUs. restart: on-failure. Robustheit: Schreibt in satellite.mbtiles.part, Umbenennung nach Abschluss. Resume-fähig. EOX liefert trotz .jpg-URL einzelne PNG-Tiles. Der Download-Container konvertiert PNG-Antworten direkt zu JPEG, damit Martin die fertige MBTiles-Datei als einheitliche Rasterquelle laden kann. Wichtige Tuning-Variablen: SAT_CHUNK und SAT_DB_BATCH begrenzen RAM/SQLite-Transaktionsgröße, SAT_JPEG_QUALITY steuert die JPEG-Qualität.

Falls eine bereits fertige Satellit-MBTiles-Datei gemischte JPEG/PNG-Tiles enthält, erst eine vollständige Sicherung erstellen und dann nur die PNG-Tiles konvertieren. Das Script ist resume-fähig: bereits konvertierte JPEG-Tiles werden bei erneutem Start übersprungen, maximal der letzte nicht committete Batch wird wiederholt.

cd /mnt/services-data/rd13_tile_server
docker compose stop martin
cp data/satellite.mbtiles data/satellite.mbtiles.backup-$(date +%Y%m%d-%H%M%S)

docker run --rm \
  -v ./data:/data \
  -v ./scripts/convert-satellite-to-jpeg.py:/convert.py:ro \
  -e SAT_CONVERT_BATCH=500 \
  -e SAT_CONVERT_SLEEP=0.02 \
  -e SAT_JPEG_QUALITY=90 \
  python:3.12-slim \
  sh -c "pip install --no-cache-dir Pillow && python3 /convert.py /data/satellite.mbtiles"

# Nach Konvertierung verifizieren
docker run --rm -v ./data:/data python:3.12-slim python3 -c \
  "import sqlite3; conn=sqlite3.connect('/data/satellite.mbtiles'); \
  fmt=conn.execute('SELECT value FROM metadata WHERE name=\"format\"').fetchone()[0]; \
  total=conn.execute('SELECT COUNT(*) FROM tiles').fetchone()[0]; \
  quick=conn.execute('PRAGMA quick_check').fetchone()[0]; \
  conn.close(); print(f'✓ format={fmt} tiles={total} quick_check={quick}')"

# Martin neu starten
docker compose up -d martin
curl -s http://localhost:9982/health

Download-Szenario (normal, neu empfohlen):

cd /mnt/services-data/rd13_tile_server

# Starten (läuft im Hintergrund, résumé-fähig, konvertiert PNG→JPEG on-the-fly)
docker compose -f docker-compose.download.yml up -d

# Status verfolgen
docker compose -f docker-compose.download.yml logs -f

# Pausieren
docker compose -f docker-compose.download.yml stop

# Fortsetzen (bereits heruntergeladene und konvertierte Tiles werden übersprungen)
docker compose -f docker-compose.download.yml up -d

# Nach Fertigstellung (check für ~5.6M Tiles, nur JPEG)
docker compose -f docker-compose.download.yml logs | tail -5
docker compose ps
curl -s http://localhost:9982/catalog | jq '.[] | select(.id == "satellite")'

Wenn fertig: data/satellite.mbtiles (~20 GB nach PNG→JPEG-Konvertierung) ist bereit. Martin lädt sie automatisch beim nächsten Restart als Source satellite.

Service Restart / Update Images

# Nur Image-Updates (Martin, tileserver-gl)
docker compose pull
docker compose up -d

# Bei Compose-Konfiguration-Änderungen
docker compose down
docker compose up -d

# Logs ansehen
docker compose logs -f martin     # Martin Vektor-API
docker compose logs -f tileserver # Raster-Rendering

Konfiguration

Tile-Server-Komponenten

Martin (Vektor-Tiles)

  • Konfiguration: config/martin.yaml
  • API Root: http://localhost:9982
  • Catalog: http://localhost:9982/catalog
  • Datenquelle: data/osm.mbtiles

tileserver-gl (Raster-PNG-Rendering)

  • Konfiguration: Styles unter data/styles/
  • API Root: http://localhost:9983 (exposed port)
  • Style osm-intl: data/styles/osm-intl.json
  • Fonts: data/fonts/
  • Sprites: data/sprites/

marker-api (Marker-PNG-Generierung)

  • Code: services/marker-api/ (Go, 0 externe Dependencies)
  • Image: 192.168.178.6:8083/cschulz/rd13_tile_server-marker-api:latest (Forgejo Registry)
  • API Root: http://localhost:9984
  • Endpunkt: /styles/v4/marker/{type}+{hexcolor}(@{scale}x).png
  • Typen: pin-s (24px), pin-m (32px), pin-l (40px); Canvas quadratisch, 80% opak, schlanke Teardrop-Form (r/d≈0.35)
  • Image neu bauen: docker compose build marker-api && docker compose up -d marker-api
  • CI: Forgejo baut + pusht automatisch bei Änderungen in services/marker-api/

Reverse Proxy (NPM) Öffentliche URLs

Konfiguration (manuell im NPM WebUI):

  1. Neuer Proxy-Host: tiles.rd13server.de

    • Forward Hostname/IP: martin (Docker-DNS)
    • Forward Port: 3000
    • Schema: http
    • Websockets Support: ☑
  2. Advanced Tab Custom Nginx Config:

    # Rate Limiting
    limit_req_zone $binary_remote_addr zone=tiles:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=tile_conn:10m;
    
    location / {
        limit_req zone=tiles burst=60 nodelay;
        limit_conn tile_conn 20;
        limit_req_status 429;
        limit_conn_status 429;
    
        # Cache-Header für Tiles
        add_header Cache-Control "public, max-age=86400, stale-while-revalidate=3600" always;
        add_header Vary "Accept-Encoding" always;
    }
    
    # Raster-Routing zu tileserver-gl
    location ~ ^/osm-intl/ {
        proxy_pass http://localhost:9983;
        proxy_ssl_server_name on;
        add_header Cache-Control "public, max-age=86400" always;
    }
    

Betrieb & Monitoring

Health-Checks manuell

# Martin Vektor-Tiles
curl -s http://localhost:9982/health

# tileserver-gl Raster
curl -s http://localhost:9983/health

# Sample-Tile abrufen (PNG)
curl -s "http://localhost:9983/osm-intl/0/0/0.png" -o /tmp/tile.png
file /tmp/tile.png

Performance-Baseline

Erwartete Antwortzeiten (ohne externen Upstream):

  • Martin /osm/{z}/{x}/{y}.pbf: <50ms (cache warm)
  • tileserver-gl /osm-intl/{z}/{x}/{y}.png: <100ms (cache cold), <20ms (cache warm)

Caches (auto-warm nach Start):

  • Martin: in-memory (fast)
  • tileserver-gl: Disk unter /tmp/pmtiles-cache (wächst mit Nutzung)

Logs

# Alle Services
docker compose logs

# Nur Fehler
docker compose logs --tail=100 | grep -i error

# Real-time verfolgen
docker compose logs -f

Nextcloud + Home Assistant Integration (Quick Rollout)

  1. Endpunkte lokal pruefen:
curl -I "http://localhost:9983/styles/osm-intl/14/8802/5373.png"
curl -I "http://localhost:9983/styles/europa-detail/16/35210/21493.png"
curl -I "http://localhost:9983/styles/satelite-world/13/4401/2686.png"
  1. Nextcloud Maps setzen:
# Im Nextcloud-Container ausfuehren
php occ config:app:set maps tileserverUrl \
  --value="https://tiles.rd13server.de/styles/europa-detail/{z}/{x}/{y}.png"
  1. Home Assistant Lovelace Tile-Layer auf einen der verifizierten Endpunkte setzen:
  • https://tiles.rd13server.de/styles/osm-intl/{z}/{x}/{y}.png
  • https://tiles.rd13server.de/styles/europa-detail/{z}/{x}/{y}.png
  • https://tiles.rd13server.de/styles/satelite-world/{z}/{x}/{y}.png
  1. Externen Test aus Browser oder HA/Nextcloud Host:
curl -I "https://tiles.rd13server.de/styles/europa-detail/16/35210/21493.png"

Troubleshooting

Problem Ursache Lösung
tiles.rd13server.de liefert 502 Martin-Container nicht erreichbar docker compose ps + docker compose logs martin
PNG-Tiles sind grau/leer tileserver-gl kann Martin nicht erreichen Docker-Network prüfen: docker network inspect rd13_tile_server_default
Lange Antwortzeiten Tile-Cache kalt, erste Render Normal; nach 1020 Requests warm; monitoring via logs
Out of Memory Cache wächst unbegrenzt tileserver-gl Speicher-Limit setzen oder Cache-TTL anpassen

Wartungsplan

Task Frequenz Aufwand
Tile-Daten aktualisieren 24×/Jahr 15 min (Script + Restart)
Container-Images patchen Wöchentlich 5 min (docker compose pull && up -d)
Logs archivieren Monatlich 5 min (via logrotate)
Disk-Space überwachen Wöchentlich 2 min (du/df)

Rollback-Procedure

Falls neue osm.mbtiles kaputt ist:

cd /mnt/services-data/rd13_tile_server
docker compose stop martin tileserver

# Alte Version zurückbringen
rm data/osm.mbtiles
mv data/osm.mbtiles.YYYYMMDD data/osm.mbtiles

docker compose up -d
Variable Pflicht Default Beschreibung
EXAMPLE_VAR Beschreibung

Persistente Daten (/data/)

Alle persistenten Daten liegen unter /data/<service>/ im Repo-Root:

Pfad Inhalt Backup-Priorität
data/<service>/ hoch/mittel/niedrig

Backup-Hinweise:

  • /data/ komplett sichern vor jedem Update
  • Empfehlung: tägliches Backup via Cron / Restic / rsync

Monitoring & Logs

# Logs ansehen
docker compose logs -f <service>

# Status prüfen
docker compose ps

Sicherheit

  • Offene Ports: …
  • TLS: …
  • Zugriffskontrolle: …

Troubleshooting

Symptom Ursache Lösung

Disaster Recovery

  1. Dienst stoppen: docker compose down
  2. Backup einspielen: …
  3. Dienst neu starten: docker compose up -d