Compare commits
No commits in common. "c01ddeed31877827b656769fd62fc0551d74b7df" and "f56f9c21b8795dc076f28892ca04b83c4bdd0131" have entirely different histories.
c01ddeed31
...
f56f9c21b8
21 changed files with 176 additions and 7572 deletions
27
.github/copilot-instructions.md
vendored
27
.github/copilot-instructions.md
vendored
|
|
@ -5,11 +5,11 @@
|
||||||
> Diese Sektion hat höchste Priorität und darf nicht ignoriert werden.
|
> Diese Sektion hat höchste Priorität und darf nicht ignoriert werden.
|
||||||
|
|
||||||
**Session START** – Bevor du irgendetwas tust:
|
**Session START** – Bevor du irgendetwas tust:
|
||||||
1. Lies `docs/history/summary/PROJECT_CONTEXT.md` (falls vorhanden)
|
1. Lies `history/summary/PROJECT_CONTEXT.md` (falls vorhanden)
|
||||||
2. Verstehe den aktuellen Projektzustand bevor du anfängst
|
2. Verstehe den aktuellen Projektzustand bevor du anfängst
|
||||||
|
|
||||||
**Session END** – Der Agent führt dies **automatisch** am Ende jeder Aufgabe aus, bevor er `git commit` ausführt:
|
**Session END** – Der Agent führt dies **automatisch** am Ende jeder Aufgabe aus, bevor er `git commit` ausführt:
|
||||||
1. Lies die bestehende `docs/history/prompts/YYYY-MM-DD_*_session.md` (falls vorhanden) und ergänze nur den neuen Teil
|
1. Lies die bestehende `history/prompts/YYYY-MM-DD_*_session.md` (falls vorhanden) und ergänze nur den neuen Teil
|
||||||
**Dateiformat zwingend:** Suffix `_session.md`, Dateiname beginnt mit heutigem Datum (`YYYY-MM-DD`)
|
**Dateiformat zwingend:** Suffix `_session.md`, Dateiname beginnt mit heutigem Datum (`YYYY-MM-DD`)
|
||||||
2. **Für jeden Benutzer-Prompt seit dem letzten Commit** einen Block ergänzen:
|
2. **Für jeden Benutzer-Prompt seit dem letzten Commit** einen Block ergänzen:
|
||||||
```
|
```
|
||||||
|
|
@ -21,9 +21,9 @@
|
||||||
```
|
```
|
||||||
⚠ Kein „Nachtrag"-Block statt echter Prompt-Einträge. Die Benutzer-Nachricht **wörtlich** zitieren.
|
⚠ Kein „Nachtrag"-Block statt echter Prompt-Einträge. Die Benutzer-Nachricht **wörtlich** zitieren.
|
||||||
⚠ Keine reinen Stichpunkt-Zusammenfassungen. Ausgeführte Kommandos und Outputs gehören **wörtlich** in die Antwort.
|
⚠ Keine reinen Stichpunkt-Zusammenfassungen. Ausgeführte Kommandos und Outputs gehören **wörtlich** in die Antwort.
|
||||||
⚠ Keine Platzhalter wie `PENDING` committen. Ist der Commit-Hash noch unbekannt: Hash weglassen oder Datei direkt nach dem Commit mit dem echten Hash aktualisieren und sofort (`git add docs/history/ && git commit`) nachziehen.
|
⚠ Keine Platzhalter wie `PENDING` committen. Ist der Commit-Hash noch unbekannt: Hash weglassen oder Datei direkt nach dem Commit mit dem echten Hash aktualisieren und sofort (`git add history/ && git commit`) nachziehen.
|
||||||
3. Aktualisiere `docs/history/summary/PROJECT_CONTEXT.md` mit dem neuen Projektstand
|
3. Aktualisiere `history/summary/PROJECT_CONTEXT.md` mit dem neuen Projektstand
|
||||||
4. **Stage beide Dateien VOR `git commit`:** `git add docs/history/`
|
4. **Stage beide Dateien VOR `git commit`:** `git add history/`
|
||||||
Der pre-commit Hook (Check 6) blockiert wenn:
|
Der pre-commit Hook (Check 6) blockiert wenn:
|
||||||
- keine `*_session.md` gestaged ist
|
- keine `*_session.md` gestaged ist
|
||||||
- der Dateiname nicht mit dem heutigen Datum beginnt
|
- der Dateiname nicht mit dem heutigen Datum beginnt
|
||||||
|
|
@ -41,23 +41,6 @@
|
||||||
- **`git push --force`** – Nie force-pushen ohne explizite Anweisung des Users.
|
- **`git push --force`** – Nie force-pushen ohne explizite Anweisung des Users.
|
||||||
- **Secrets in Code** – Keine Passwörter, API-Keys, Tokens in Dateien.
|
- **Secrets in Code** – Keine Passwörter, API-Keys, Tokens in Dateien.
|
||||||
|
|
||||||
## ⚠ Bekannte Fallstricke (nicht vergessen!)
|
|
||||||
|
|
||||||
- **Scripts mit Self-Update (`copilot-update.sh/.fish`) immer erst committen+pushen, DANN manuell deployen.**
|
|
||||||
Reihenfolge zwingend:
|
|
||||||
1. Änderung im Repo vornehmen
|
|
||||||
2. `git add … && git commit && git push`
|
|
||||||
3. `cp scripts/copilot-update.sh ~/.local/bin/copilot-update.sh`
|
|
||||||
4. Testen
|
|
||||||
Falsche Reihenfolge (erst deployen, dann committen) → Self-Update überschreibt den manuell deployten Fix
|
|
||||||
mit der alten Version aus dem Remote-Cache. Der Fix geht verloren.
|
|
||||||
|
|
||||||
- **`fi ───` oder `end ───` in POSIX-sh/fish:** Box-Drawing-Zeichen nie direkt ans `fi`/`end` anhängen.
|
|
||||||
Kommentar-Trennlinie immer auf eigener Zeile: `# ── Abschnitt ──`
|
|
||||||
|
|
||||||
- **`printf '%s\n%s\n'` frisst trailing newlines** aus `$(awk ...)` Substitution.
|
|
||||||
Wenn eine Leerzeile zwischen zwei Blöcken erhalten bleiben soll: `printf '%s\n\n%s\n'` verwenden.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Project
|
## Project
|
||||||
|
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,9 +1,6 @@
|
||||||
# Datendateien – nicht im Repo (können mehrere GB groß sein)
|
# Datendateien – nicht im Repo (können mehrere GB groß sein)
|
||||||
data/*
|
data/*
|
||||||
|
|
||||||
# Planetiler Build-Output (Host-Build, nicht auf dem Server)
|
|
||||||
build/
|
|
||||||
|
|
||||||
# Laufzeit
|
# Laufzeit
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"options": {
|
|
||||||
"paths": {
|
|
||||||
"fonts": "/data/fonts",
|
|
||||||
"sprites": "/data/sprites",
|
|
||||||
"styles": "/data/styles",
|
|
||||||
"mbtiles": "/data"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"osm-intl": {
|
|
||||||
"style": "osm-intl.json"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"osm": {
|
|
||||||
"mbtiles": "osm.mbtiles"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
# Planetiler Build – Vektor-Tiles für höhere Zoom-Level
|
|
||||||
#
|
|
||||||
# LÄUFT AUF DEM HOST-RECHNER (nicht auf dem Server).
|
|
||||||
# Voraussetzung: Docker Desktop (macOS/Windows) oder Docker Engine (Linux)
|
|
||||||
#
|
|
||||||
# ══════════════════════════════════════════════════════════════════════
|
|
||||||
# DISK-ANFORDERUNGEN (auf dem Host-Rechner)
|
|
||||||
# ══════════════════════════════════════════════════════════════════════
|
|
||||||
#
|
|
||||||
# AREA=germany MAX_ZOOM=16: ~30 GB temp + ~12 GB output = ~50 GB frei
|
|
||||||
# AREA=europe MAX_ZOOM=16: ~200 GB temp + ~80 GB output = ~350 GB frei
|
|
||||||
# AREA=planet MAX_ZOOM=15: ~200 GB temp + ~80 GB output = ~350 GB frei
|
|
||||||
# AREA=planet MAX_ZOOM=16: ~500 GB temp + ~300 GB output = ~900 GB frei
|
|
||||||
#
|
|
||||||
# ══════════════════════════════════════════════════════════════════════
|
|
||||||
# SCHRITT 1: Build starten
|
|
||||||
# ══════════════════════════════════════════════════════════════════════
|
|
||||||
#
|
|
||||||
# # Germany z0-16 (empfohlen als Einstieg)
|
|
||||||
# AREA=germany MAX_ZOOM=16 RAM=8g docker compose -f docker-compose.build.yml up
|
|
||||||
#
|
|
||||||
# # Planet z0-15 (~80 GB Output, ~8h, 28 GB RAM, ~350 GB Temp+Output Disk)
|
|
||||||
# AREA=planet MAX_ZOOM=15 RAM=28g BUILD_CPUS=12 BUILD_MEM=30g \
|
|
||||||
# docker compose -f docker-compose.build.yml up
|
|
||||||
#
|
|
||||||
# # Planet z0-16 (~300 GB Output, ~15h, 28 GB RAM, ~900 GB Temp+Output Disk)
|
|
||||||
# AREA=planet MAX_ZOOM=16 RAM=28g BUILD_CPUS=12 BUILD_MEM=30g \
|
|
||||||
# docker compose -f docker-compose.build.yml up
|
|
||||||
#
|
|
||||||
# Status verfolgen (zweites Terminal):
|
|
||||||
# docker compose -f docker-compose.build.yml logs -f
|
|
||||||
#
|
|
||||||
# ══════════════════════════════════════════════════════════════════════
|
|
||||||
# SCHRITT 2: Ergebnis auf Server übertragen
|
|
||||||
# ══════════════════════════════════════════════════════════════════════
|
|
||||||
#
|
|
||||||
# rsync -avh --progress --partial \
|
|
||||||
# ./build/output/<AREA>.mbtiles \
|
|
||||||
# rd13server@192.168.178.6:/mnt/services-data/rd13_tile_server/data/osm-<AREA>.mbtiles
|
|
||||||
#
|
|
||||||
# ══════════════════════════════════════════════════════════════════════
|
|
||||||
# SCHRITT 3: 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 -i area
|
|
||||||
|
|
||||||
services:
|
|
||||||
planetiler-build:
|
|
||||||
image: ghcr.io/onthegomap/planetiler:latest
|
|
||||||
container_name: rd13_planetiler_build
|
|
||||||
volumes:
|
|
||||||
# Output: fertige MBTiles
|
|
||||||
- ./build/output:/output
|
|
||||||
# Source-Cache: OSM-PBF wird hier gecacht (verhindert Re-Download bei Neustart)
|
|
||||||
- ./build/sources:/data/sources
|
|
||||||
# Temp: sehr viel Platz nötig (siehe Tabelle oben)
|
|
||||||
- ./build/tmp:/data/tmp
|
|
||||||
environment:
|
|
||||||
- JAVA_TOOL_OPTIONS=-Xmx${RAM:-8g} -Xms2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
|
|
||||||
command:
|
|
||||||
- "--download"
|
|
||||||
- "--area=${AREA:-germany}"
|
|
||||||
- "--output=/output/${AREA:-germany}.mbtiles"
|
|
||||||
- "--maxzoom=${MAX_ZOOM:-16}"
|
|
||||||
- "--nodemap-type=sortedtable"
|
|
||||||
- "--force"
|
|
||||||
restart: "no"
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpus: "${BUILD_CPUS:-4.0}"
|
|
||||||
memory: ${BUILD_MEM:-12g}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
# Satellite-Download – eigenständiger Container
|
|
||||||
#
|
|
||||||
# Läuft vollständig unabhängig von VS Code / SSH-Sessions.
|
|
||||||
# Resume-fähig: bereits heruntergeladene Tiles werden übersprungen.
|
|
||||||
#
|
|
||||||
# STARTEN:
|
|
||||||
# cd /mnt/services-data/rd13_tile_server
|
|
||||||
# docker compose -f docker-compose.download.yml up
|
|
||||||
#
|
|
||||||
# STATUS (in zweitem Terminal):
|
|
||||||
# docker compose -f docker-compose.download.yml logs -f
|
|
||||||
#
|
|
||||||
# STOPPEN (Download pausieren):
|
|
||||||
# docker compose -f docker-compose.download.yml stop
|
|
||||||
#
|
|
||||||
# FORTSETZEN:
|
|
||||||
# docker compose -f docker-compose.download.yml up
|
|
||||||
#
|
|
||||||
# ERGEBNIS:
|
|
||||||
# data/satellite.mbtiles (~38 GB bei MAX_ZOOM=11)
|
|
||||||
|
|
||||||
services:
|
|
||||||
satellite-download:
|
|
||||||
image: python:3.12-slim
|
|
||||||
container_name: rd13_satellite_download
|
|
||||||
volumes:
|
|
||||||
- ./data:/data
|
|
||||||
- ./scripts:/scripts:ro
|
|
||||||
- ./logs:/logs
|
|
||||||
environment:
|
|
||||||
- SAT_MAX_ZOOM=11
|
|
||||||
- SAT_THREADS=16
|
|
||||||
- PYTHONUNBUFFERED=1
|
|
||||||
command: ["python3", "-u", "/scripts/download-satellite.py", "/data/satellite.mbtiles"]
|
|
||||||
restart: "no"
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpus: "4.0"
|
|
||||||
memory: 2048M
|
|
||||||
reservations:
|
|
||||||
memory: 128M
|
|
||||||
|
|
@ -15,24 +15,3 @@ services:
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 10s
|
start_period: 10s
|
||||||
|
|
||||||
tileserver:
|
|
||||||
image: maptiler/tileserver-gl:latest
|
|
||||||
container_name: rd13_tileserver
|
|
||||||
ports:
|
|
||||||
- "9983:8080"
|
|
||||||
volumes:
|
|
||||||
- ./config/tileserver.json:/data/config.json:ro
|
|
||||||
- ./config/styles:/data/styles:ro
|
|
||||||
- ./data/fonts:/data/fonts:ro
|
|
||||||
- ./data/sprites:/data/sprites:ro
|
|
||||||
- ./data/osm.mbtiles:/data/osm.mbtiles:ro
|
|
||||||
restart: unless-stopped
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "node", "-e", "require('http').get('http://localhost:8080/health', r => process.exit(r.statusCode === 200 ? 0 : 1))"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
start_period: 30s
|
|
||||||
depends_on:
|
|
||||||
- martin
|
|
||||||
|
|
|
||||||
263
docs/ADMIN.md
263
docs/ADMIN.md
|
|
@ -1,19 +1,20 @@
|
||||||
# Administrator-Handbuch – rd13_tile_server
|
# Administrator-Handbuch – [PROJEKT_NAME]
|
||||||
|
|
||||||
> Zielgruppe: **Administratoren** – Menschen, die das System betreiben, deployen und konfigurieren.
|
> Zielgruppe: **Administratoren** – Menschen, die das System betreiben, deployen und konfigurieren.
|
||||||
> Voraussetzung: Grundkenntnisse in Linux, Docker und der eingesetzten Stack (Martin, tileserver-gl).
|
> Voraussetzung: Grundkenntnisse in Linux, Docker und dem eingesetzten Stack.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Systemvoraussetzungen
|
## Systemvoraussetzungen
|
||||||
|
|
||||||
|
<!-- TODO: Anforderungen an Host/Server -->
|
||||||
|
|
||||||
| Komponente | Mindestanforderung | Empfohlen |
|
| Komponente | Mindestanforderung | Empfohlen |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| OS | Linux 5.10+ (oder macOS 12+) | Ubuntu 22.04 LTS |
|
| OS | … | … |
|
||||||
| RAM | 1 GB | 2-4 GB |
|
| RAM | … | … |
|
||||||
| Disk | 5 GB (OS + Containers) | 20 GB (mit Cache-Warmup) |
|
| Disk | … | … |
|
||||||
| Dependencies | Docker 20.10+, docker-compose 2.0+ | Docker Desktop / Compose v2 |
|
| Dependencies | … | … |
|
||||||
| Network | Port 9982 (Martin), Port 8080 (tileserver-gl) internal | Public domain via NPM reverse proxy |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -21,256 +22,32 @@
|
||||||
|
|
||||||
### Erstes Aufsetzen
|
### Erstes Aufsetzen
|
||||||
|
|
||||||
|
<!-- TODO: Schritt-für-Schritt Deployment -->
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Repository klonen
|
# Beispiel
|
||||||
git clone ssh://git@192.168.178.6:2222/cschulz/rd13_tile_server.git /mnt/services-data/rd13_tile_server
|
git clone <repo> /opt/service
|
||||||
cd /mnt/services-data/rd13_tile_server
|
cd /opt/service
|
||||||
|
cp .env.example .env
|
||||||
# Daten-Verzeichnis initialisieren (falls nicht vorhanden)
|
# .env ausfüllen!
|
||||||
mkdir -p data/{fonts,sprites,styles}
|
|
||||||
|
|
||||||
# Services starten
|
|
||||||
docker compose up -d
|
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)
|
### Updates einspielen
|
||||||
|
|
||||||
**Szenario: osm.mbtiles aktualisieren (2–4×/Jahr)**
|
<!-- TODO: Update-Prozedur -->
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Neue MBTiles herunterladen (z.B. von OpenFreeMap)
|
git pull
|
||||||
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, ~8–12h, 12 CPUs / 28 GB RAM
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 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).
|
|
||||||
|
|
||||||
### 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, 2 GB RAM-Limit, 4 CPUs – konfigurierbar in `docker-compose.download.yml`.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /mnt/services-data/rd13_tile_server
|
|
||||||
|
|
||||||
# Starten (läuft im Vordergrund, Logs direkt sichtbar)
|
|
||||||
docker compose -f docker-compose.download.yml up
|
|
||||||
|
|
||||||
# Status in zweitem Terminal verfolgen
|
|
||||||
docker compose -f docker-compose.download.yml logs -f
|
|
||||||
|
|
||||||
# Pausieren
|
|
||||||
docker compose -f docker-compose.download.yml stop
|
|
||||||
|
|
||||||
# Fortsetzen (bereits heruntergeladene Tiles werden übersprungen)
|
|
||||||
docker compose -f docker-compose.download.yml up
|
|
||||||
```
|
|
||||||
|
|
||||||
Wenn fertig: `data/satellite.mbtiles` (~38 GB) liegt bereit.
|
|
||||||
Martin lädt sie automatisch beim nächsten Restart als Source `satellite`.
|
|
||||||
|
|
||||||
|
|
||||||
### Service Restart / Update Images
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Nur Image-Updates (Martin, tileserver-gl)
|
|
||||||
docker compose pull
|
docker compose pull
|
||||||
docker compose up -d
|
docker compose up -d --force-recreate
|
||||||
|
|
||||||
# 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
|
## Konfiguration
|
||||||
|
|
||||||
### Tile-Server-Komponenten
|
### Umgebungsvariablen (`.env`)
|
||||||
|
|
||||||
**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/`
|
|
||||||
|
|
||||||
### 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:**
|
|
||||||
```nginx
|
|
||||||
# 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
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 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
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Alle Services
|
|
||||||
docker compose logs
|
|
||||||
|
|
||||||
# Nur Fehler
|
|
||||||
docker compose logs --tail=100 | grep -i error
|
|
||||||
|
|
||||||
# Real-time verfolgen
|
|
||||||
docker compose logs -f
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 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 10–20 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 | 2–4×/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:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- TODO: Alle relevanten Env-Vars dokumentieren -->
|
<!-- TODO: Alle relevanten Env-Vars dokumentieren -->
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,268 +1,53 @@
|
||||||
# Maintainer-Handbuch – rd13_tile_server
|
# Maintainer-Handbuch – [PROJEKT_NAME]
|
||||||
|
|
||||||
> Zielgruppe: **Entwickler & Maintainer** – Menschen, die den Code verstehen, erweitern oder reviewen.
|
> Zielgruppe: **Entwickler & Maintainer** – Menschen, die den Code verstehen, erweitern oder reviewen.
|
||||||
> Voraussetzung: Entwicklungserfahrung mit Docker, MapLibre GL Styles, OSM-Daten.
|
> Voraussetzung: Entwicklungserfahrung mit dem eingesetzten Stack.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Architektur – Martin + tileserver-gl Stack
|
## Architektur
|
||||||
|
|
||||||
|
<!-- TODO: Beschreibe die Architektur (C4, Hexagonal, Event-Driven, etc.) -->
|
||||||
|
|
||||||
```
|
```
|
||||||
Internet (HTTPS)
|
┌──────────────────────────────────────────────────────────┐
|
||||||
↓
|
│ TODO: Architektur-Diagramm (ASCII oder Mermaid) │
|
||||||
NPM Reverse Proxy (tiles.rd13server.de, Rate Limiting)
|
└──────────────────────────────────────────────────────────┘
|
||||||
├─ /osm/{z}/{x}/{y}.pbf → Martin (Vektor-Tiles)
|
|
||||||
└─ /osm-intl/{z}/{x}/{y}.png → tileserver-gl (Raster-PNG)
|
|
||||||
↓
|
|
||||||
tileserver-gl renders Martin Vektor → PNG
|
|
||||||
↓
|
|
||||||
Martin reads osm.mbtiles (Vector Tiles)
|
|
||||||
↓
|
|
||||||
/data/osm.mbtiles (OpenFreeMap snapshot)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Stack-Komponenten:**
|
**Wichtige Komponenten:**
|
||||||
|
|
||||||
| Komponente | Input | Output | Verantwortung |
|
| Komponente | Verantwortlichkeit | Ort |
|
||||||
|---|---|---|---|
|
|---|---|---|
|
||||||
| **Martin** | `osm.mbtiles` | `/{layer}/{z}/{x}/{y}.pbf` | Vektor-API, Tile-Distribution |
|
| … | … | `src/…` |
|
||||||
| **tileserver-gl** | Martin PBF + `osm-intl.json` | `/{style}/{z}/{x}/{y}.png` | Rendering, PNG-Tile-Cache |
|
|
||||||
| **NPM** | HTTP Client Requests | HTTPS Responses | Proxy, SSL, Rate-Limit |
|
|
||||||
|
|
||||||
**Verwandte ADRs:**
|
|
||||||
- [ADR-001: Tile Rendering Stack – Martin + tileserver-gl](docs/adr/001-martin-tileserver-gl-stack.md)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Projektstruktur
|
## Projektstruktur
|
||||||
|
|
||||||
```
|
```
|
||||||
rd13_tile_server/
|
[PROJEKT_NAME]/
|
||||||
├── config/
|
├── data/ ← Persistente Daten (gitignored)
|
||||||
│ └── martin.yaml ← Martin Server-Konfiguration
|
│ └── <service>/ ← Ein Unterordner pro Service
|
||||||
├── data/
|
|
||||||
│ ├── osm.mbtiles ← OpenFreeMap Vector-Snapshot (~94 GB)
|
|
||||||
│ ├── styles/
|
|
||||||
│ │ └── osm-intl.json ← MapLibre GL Style für Raster-Rendering
|
|
||||||
│ ├── fonts/
|
|
||||||
│ │ ├── Metropolis Black/
|
|
||||||
│ │ ├── Open Sans Regular/
|
|
||||||
│ │ └── … (47 weitere Font-Varianten)
|
|
||||||
│ └── sprites/ ← Marker/Icons (derzeit leer)
|
|
||||||
├── docs/
|
├── docs/
|
||||||
│ ├── adr/
|
│ ├── USER.md ← Endnutzer-Dokumentation
|
||||||
│ │ ├── 000-template.md
|
│ ├── ADMIN.md ← Administrator-Dokumentation
|
||||||
│ │ └── 001-martin-tileserver-gl-stack.md
|
│ └── MAINTAINER.md ← Dieses Dokument
|
||||||
│ ├── history/
|
├── history/
|
||||||
│ ├── requirements/
|
│ ├── prompts/ ← Vollständige Agent-Konversationen (gitignored)
|
||||||
│ │ └── REQUIREMENTS.md
|
│ └── summary/
|
||||||
│ ├── USER.md, ADMIN.md, MAINTAINER.md
|
│ └── PROJECT_CONTEXT.md ← Aktueller Projektzustand für Agent-Kontext
|
||||||
│ └── … (API-Endpoints, Integration-Guides)
|
└── … ← Source Code
|
||||||
├── docker-compose.yml ← Martin + tileserver-gl
|
|
||||||
└── scripts/
|
|
||||||
├── download-data.sh ← OSM-MBTiles fetcher
|
|
||||||
└── download-satellite.py ← Satellit-MBTiles fetcher (optional)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Style-Customization (osm-intl.json)
|
## Entwicklungsumgebung aufsetzen
|
||||||
|
|
||||||
Die Kartographer-Karten werden von `data/styles/osm-intl.json` definiert. Das ist eine Standard **MapLibre GL Style** (v8-kompatibel).
|
<!-- TODO: Wie richtet man die lokale Entwicklungsumgebung ein? -->
|
||||||
|
|
||||||
### Tipps zum Ändern
|
|
||||||
|
|
||||||
**1. Farben anpassen** (einfach)
|
|
||||||
|
|
||||||
```json
|
|
||||||
"layers": [
|
|
||||||
{
|
|
||||||
"id": "water-area",
|
|
||||||
"paint": {
|
|
||||||
"fill-color": "#b0d4fc" ← Ändere zu z.B. "#0066cc"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Layer-Sichtbarkeit nach Zoom-Level** (mittelschwer)
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "poi-icon",
|
|
||||||
"minzoom": 14, ← POI-Icons nur ab Zoom 14 sichtbar
|
|
||||||
"maxzoom": 20 ← Max Zoom-Level
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. Label-Schriftart** (mittelschwer)
|
|
||||||
|
|
||||||
```json
|
|
||||||
"text-font": ["Open Sans Bold"] ← Verfügbare Fonts in data/fonts/
|
|
||||||
```
|
|
||||||
|
|
||||||
**Verfügbare Fonts** (aus `/data/fonts/`):
|
|
||||||
- Metropolis (Black, Bold, Light, Regular, Thin + Italic-Varianten)
|
|
||||||
- Open Sans (Bold, Regular, Semibold + Italic-Varianten)
|
|
||||||
- PT Sans (Bold, Caption, Regular, Narrow + Varianten)
|
|
||||||
- Roboto (Black, Bold, Light, Medium, Regular, Thin + Italic-Varianten)
|
|
||||||
- Noto Sans (Bold, Italic, Regular)
|
|
||||||
|
|
||||||
**4. Linien-Dicke nach Zoom-Level** (fortgeschritten)
|
|
||||||
|
|
||||||
```json
|
|
||||||
"line-width": [
|
|
||||||
"interpolate", ← Interpolations-Funktion
|
|
||||||
["linear"], ← Linear interpolieren
|
|
||||||
["zoom"], ← Input: aktueller Zoom-Level
|
|
||||||
6, 0.5, ← Bei Zoom 6: 0.5px
|
|
||||||
20, 6 ← Bei Zoom 20: 6px
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Style testen (lokal)
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Nach Änderungen an osm-intl.json:
|
git clone <repo>
|
||||||
docker compose restart tileserver
|
|
||||||
|
|
||||||
# PNG-Tile abrufen
|
|
||||||
curl -s "http://localhost:9983/osm-intl/10/544/335.png" -o /tmp/test.png
|
|
||||||
file /tmp/test.png
|
|
||||||
|
|
||||||
# In MediaWiki-Kartographer URL testen:
|
|
||||||
# https://tiles.rd13server.de/osm-intl/{z}/{x}/{y}.png
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Martin Vector-Source verstehen
|
|
||||||
|
|
||||||
Martin liest Vektor-Daten aus `osm.mbtiles` und serviert sie als PBF (Protocol Buffers).
|
|
||||||
|
|
||||||
**Available Layers in osm.mbtiles** (abhängig von OpenFreeMap-Schema):
|
|
||||||
|
|
||||||
Beispiel: `http://localhost:9982/catalog` zeigt alle Source-Layer.
|
|
||||||
|
|
||||||
Typisch enthalten:
|
|
||||||
- `water` – Seen, Flüsse
|
|
||||||
- `landuse` – Wald, Park, Gras, Acker
|
|
||||||
- `building` – Gebäude-Polygone
|
|
||||||
- `road` – Straßen (Motorway, Trunk, Primary, Secondary, etc.)
|
|
||||||
- `railway` – Eisenbahn-Linien
|
|
||||||
- `place` – Orte (City, Town, Village)
|
|
||||||
- `poi` – Points of Interest
|
|
||||||
|
|
||||||
**Layer in osm-intl.json updaten:**
|
|
||||||
|
|
||||||
```json
|
|
||||||
"source": "osm", ← Vector-Tile-Source (Martin)
|
|
||||||
"source-layer": "water", ← Welcher OSM-Layer? (prüfe /catalog)
|
|
||||||
```
|
|
||||||
|
|
||||||
Falls Layer fehlt → `http://localhost:9982/catalog` prüfen, oder mit `layer` in osm-intl.json experimential einen neuen hinzufügen.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Rendering-Performance tunen
|
|
||||||
|
|
||||||
**tileserver-gl Cache:**
|
|
||||||
|
|
||||||
- **Disk-Cache:** `/tmp/pmtiles-cache` (wächst mit Nutzung; max ~50 GB bei voller Coverage)
|
|
||||||
- **Memory:** ~500 MB standard, skaliert mit Anfrage-Load
|
|
||||||
- **Warm-up:** Erste Anfrage zu neuem Tile-Bereich ist langsam (~100–200ms), danach <20ms
|
|
||||||
|
|
||||||
**Bottleneck identifizieren:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Logs verfolgen (live)
|
|
||||||
docker compose logs -f tileserver | grep "render"
|
|
||||||
|
|
||||||
# Performance der Martin-API
|
|
||||||
curl -w "Time: %{time_total}s\n" -s http://localhost:9982/osm/0/0/0 | head
|
|
||||||
```
|
|
||||||
|
|
||||||
**Falls zu langsam:**
|
|
||||||
1. Martin-Worker-Prozesse erhöhen: `config/martin.yaml` → `worker_processes`
|
|
||||||
2. tileserver-gl Memory erhöhen: docker-compose.yml → `deploy.resources.limits.memory`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Tests & Validierung
|
|
||||||
|
|
||||||
### Tile-Integrität checken
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Vektor-Tile (PBF) abrufen und inspizieren
|
|
||||||
curl -s "http://localhost:9982/osm/0/0/0.pbf" | file -
|
|
||||||
# Should: PBF (Tile protocol buffer)
|
|
||||||
|
|
||||||
# Raster-Tile (PNG) abrufen und prüfen
|
|
||||||
curl -s "http://localhost:8080/osm-intl/0/0/0.png" -o /tmp/t.png
|
|
||||||
file /tmp/t.png
|
|
||||||
# Should: image/png
|
|
||||||
|
|
||||||
# MediaWiki-Test URL
|
|
||||||
# https://tiles.rd13server.de/osm-intl/0/0/0.png
|
|
||||||
```
|
|
||||||
|
|
||||||
### Smoke-Test nach Update
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Nach Tile-Daten-Update (osm.mbtiles):
|
|
||||||
for zoom in 0 5 10 14; do
|
|
||||||
curl -s "http://localhost:9983/osm-intl/$zoom/0/0.png" \
|
|
||||||
-o /tmp/test_z$zoom.png && echo "✓ Zoom $zoom" || echo "✗ Zoom $zoom"
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Deployment & Release
|
|
||||||
|
|
||||||
### Checklist vor Push
|
|
||||||
|
|
||||||
- [ ] `docker compose logs` prüfen – keine Errors
|
|
||||||
- [ ] Test-Tiles (Zoom 0, 5, 10, 14) erfolgreich
|
|
||||||
- [ ] REQUIREMENTS.md aktualisiert (falls Anforderung geändert)
|
|
||||||
- [ ] ADR erstellt (falls architektur-relevant)
|
|
||||||
- [ ] ADMIN.md / MAINTAINER.md aktualisiert
|
|
||||||
- [ ] CHANGELOG.md aktualisiert (falls vorhanden)
|
|
||||||
- [ ] Git commit + push
|
|
||||||
|
|
||||||
### Version & Releases
|
|
||||||
|
|
||||||
Derzeit: `rolling release` (jeder Commit ist live).
|
|
||||||
|
|
||||||
Falls später strikte Versionierung nötig:
|
|
||||||
- Versioning: Semantic Versioning (MAJOR.MINOR.PATCH)
|
|
||||||
- Releases: Tag in Git + Changelog
|
|
||||||
- Example: `v1.0.0` (Martin 0.9.0 + tileserver-gl 4.7.0)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Bekannte Limitations & Future TODOs
|
|
||||||
|
|
||||||
**Jetzt (ADR-001):**
|
|
||||||
- ✅ Martin + tileserver-gl für statische 2–4×/Year Updates
|
|
||||||
- ✅ Styles anpassbar (osm-intl.json)
|
|
||||||
- ✅ Fonts + Sprites nutzbar
|
|
||||||
|
|
||||||
**Zukünftig (Falls nötig):**
|
|
||||||
- [ ] **ADR-002:** Live OSM-Update-Pipeline (OpenMapTiles Server)
|
|
||||||
- [ ] Sprites/Icons erweitern (derzeit leer)
|
|
||||||
- [ ] Mehrere Styles pro Kartographie-Kontext (dark mode, print-optimized)
|
|
||||||
- [ ] Horizontal scaling (Kubernetes / Load Balancer)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Ressourcen
|
|
||||||
|
|
||||||
- [Martin Tile Server Documentation](https://maplibre.org/martin/)
|
|
||||||
- [tileserver-gl Documentation](https://tileserver.readthedocs.io/)
|
|
||||||
- [MapLibre GL Style Specification v8](https://maplibre.org/maplibre-gl-js-docs/style-spec/)
|
|
||||||
- [OpenMapTiles Schema](https://openmaptiles.org/schema/)
|
|
||||||
- [OSM Wiki: Map Tiles](https://wiki.openstreetmap.org/wiki/Tiles)
|
|
||||||
cd <repo>
|
cd <repo>
|
||||||
# Dependencies installieren
|
# Dependencies installieren
|
||||||
# Dev-Server starten
|
# Dev-Server starten
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
# ADR Template
|
|
||||||
|
|
||||||
Record architectural decisions for the tile server project using this template.
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
**Status:** [Proposed | Accepted | Deprecated | Superseded by ADR-XXX]
|
|
||||||
|
|
||||||
## Context
|
|
||||||
|
|
||||||
Describe the issue or problem that motivated this decision. Include relevant background,
|
|
||||||
constraints, and the business/technical drivers.
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
|
|
||||||
State the architectural decision clearly. What are we doing and why?
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
|
|
||||||
### Benefits
|
|
||||||
- Positive outcome 1
|
|
||||||
- Positive outcome 2
|
|
||||||
|
|
||||||
### Drawbacks
|
|
||||||
- Negative consequence 1
|
|
||||||
- Negative consequence 2
|
|
||||||
|
|
||||||
## Alternatives Considered
|
|
||||||
|
|
||||||
### Option A: [Name]
|
|
||||||
- Pros: ...
|
|
||||||
- Cons: ...
|
|
||||||
- Why not chosen: ...
|
|
||||||
|
|
||||||
### Option B: [Name]
|
|
||||||
- Pros: ...
|
|
||||||
- Cons: ...
|
|
||||||
- Why not chosen: ...
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- Link to related docs, RFCs, or issues
|
|
||||||
- External references if applicable
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
# 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 2–4 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 2–4×/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; 3–5 GB footprint
|
|
||||||
- **High setup cost** – 3–5 days to operationalize + ongoing maintenance burden
|
|
||||||
- **Not needed yet** – static 2–4×/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
|
|
||||||
|
|
||||||
- [Martin Tile Server Docs](https://maplibre.org/martin/)
|
|
||||||
- [tileserver-gl Docs](https://tileserver.readthedocs.io/)
|
|
||||||
- [REQ-001: Tile Server öffentlich erreichbar](../requirements/REQUIREMENTS.md#req-001)
|
|
||||||
- [REQ-004: MediaWiki Integration](../requirements/REQUIREMENTS.md#req-004)
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
# ADR-002: Kein Selbst-Build für z16-Extrakte und Satelliten-Tiles
|
|
||||||
|
|
||||||
**Date:** 2026-06-13
|
|
||||||
**Status:** Accepted
|
|
||||||
|
|
||||||
## Context
|
|
||||||
|
|
||||||
Es wurden zwei Erweiterungen evaluiert:
|
|
||||||
|
|
||||||
1. **OSM Vektor-Tiles für Europa/Deutschland bis Zoom 16**
|
|
||||||
Zoom 16 liefert Details wie Hausnummern, Fußwege, einzelne Gebäudeumrisse –
|
|
||||||
deutlich mehr Detail als das vorhandene Planet-MBTiles (z0–14).
|
|
||||||
|
|
||||||
2. **Satelliten-Raster-Tiles für den gesamten Planeten**
|
|
||||||
Satellitenkarte als zweiter Kartenstil in Kartographer und Home Assistant.
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
|
|
||||||
**Beide Optionen werden auf der aktuellen Hardware nicht gebaut (Self-Build ausgeschlossen).**
|
|
||||||
|
|
||||||
### Begründung
|
|
||||||
|
|
||||||
#### z16 Vektor-Europa/Deutschland
|
|
||||||
|
|
||||||
| Quelle | Verfügbar? | Anmerkung |
|
|
||||||
|---|---|---|
|
|
||||||
| OpenFreeMap Download | ❌ | Nur Planet z0–14 |
|
|
||||||
| Protomaps PMTiles | ❌ | Täglich Planet, aber max. z14–15 |
|
|
||||||
| Geofabrik | ❌ | Nur OSM-Rohdaten (PBF), keine Tiles |
|
|
||||||
| Planetiler Self-Build | ❌ ausgeschlossen | RAM-Anforderung: ≥16 GB (Europa), ≥64 GB (Planet); Buildzeit: 8–12h Europa |
|
|
||||||
|
|
||||||
**Ergebnis:** Kein freier Pre-Build verfügbar. Selbst-Build auf aktueller Hardware nicht möglich.
|
|
||||||
|
|
||||||
#### Satelliten-Planet
|
|
||||||
|
|
||||||
| Quelle | Verfügbar? | Anmerkung |
|
|
||||||
|---|---|---|
|
|
||||||
| Pre-built Planet MBTiles | ❌ | Kein Anbieter bietet komplettes Planet-Satellit-MBTiles |
|
|
||||||
| EOX Sentinel-2 (tile-by-tile) | ✅ z0–11 | Download via `download-satellite.py`, ~38 GB, ~24h |
|
|
||||||
| EOX Sentinel-2 z12 | ⚠️ möglich | ~140 GB, 3–5 Tage Download, grenzwertig |
|
|
||||||
| EOX Sentinel-2 z13+ | ❌ | Nicht praktikabel (TB-Bereich) |
|
|
||||||
|
|
||||||
**Ergebnis:** Kein Planet-Download verfügbar. Tile-by-tile z0–11 ist die einzige praktikable Option (~38 GB).
|
|
||||||
|
|
||||||
### Hardware-Einschränkung (dokumentiert)
|
|
||||||
|
|
||||||
Die aktuelle Hardware (`rd13docker`) erfüllt die Mindestanforderungen für
|
|
||||||
Planetiler-Builds nicht:
|
|
||||||
|
|
||||||
| Anforderung | Planetiler Europa | Aktuell verfügbar |
|
|
||||||
|---|---|---|
|
|
||||||
| RAM | ≥ 16 GB | nicht bekannt / begrenzt |
|
|
||||||
| SSD-Temp | ≥ 500 GB | begrenzt |
|
|
||||||
| Buildzeit | 8–12h | akzeptabel, aber RAM ist Blocker |
|
|
||||||
|
|
||||||
**Diese Einschränkung ist dauerhaft in diesem ADR festgehalten.**
|
|
||||||
Kein Agent oder Maintainer soll einen Planetiler-Build auf dieser Hardware starten.
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
|
|
||||||
### Was bleibt
|
|
||||||
|
|
||||||
- **Vektor-Planet z0–14** bleibt die Datenbasis (OpenFreeMap, 95 GB, vorhanden)
|
|
||||||
- **Satelliten-Download z0–11** kann jederzeit gestartet werden (Script vorhanden)
|
|
||||||
|
|
||||||
### Akzeptierte Einschränkungen
|
|
||||||
|
|
||||||
- Zoom 15–16 (Hausnummern, Einfahrten) nicht verfügbar → akzeptiert
|
|
||||||
- Satellitkarte maximal z11 (Stadtebene ohne Straßendetail) → akzeptiert
|
|
||||||
- Kein Live-OSM-Update-Zyklus (separat: ADR-001)
|
|
||||||
|
|
||||||
## Zukunft / Upgrade-Pfad
|
|
||||||
|
|
||||||
Falls Hardware aufgerüstet wird (≥ 16 GB RAM, ≥ 500 GB SSD-Temp):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Deutschland z0-16 (~12 GB Output, ~2h, 8 GB RAM)
|
|
||||||
docker run --rm -v ./data:/data \
|
|
||||||
-e JAVA_TOOL_OPTIONS="-Xmx8g" \
|
|
||||||
ghcr.io/onthegomap/planetiler:latest \
|
|
||||||
--download --area=germany --output=/data/osm-de.mbtiles
|
|
||||||
|
|
||||||
# Europa z0-16 (~80 GB Output, ~12h, 16 GB RAM)
|
|
||||||
docker run --rm -v ./data:/data \
|
|
||||||
-e JAVA_TOOL_OPTIONS="-Xmx16g" \
|
|
||||||
ghcr.io/onthegomap/planetiler:latest \
|
|
||||||
--download --area=europe --output=/data/osm-eu.mbtiles
|
|
||||||
```
|
|
||||||
|
|
||||||
Satellit z0–11 (jetzt möglich, Script vorhanden):
|
|
||||||
```bash
|
|
||||||
SAT_MAX_ZOOM=11 python3 scripts/download-satellite.py data/satellite.mbtiles
|
|
||||||
# Schätzung: ~38 GB, ~24h bei 8 Threads
|
|
||||||
```
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- [ADR-001: Martin + tileserver-gl Stack](001-martin-tileserver-gl-stack.md)
|
|
||||||
- [OpenFreeMap Downloads](https://openfreemap.org) – nur Planet z0–14
|
|
||||||
- [Protomaps Builds](https://maps.protomaps.com/builds/) – nur Planet z0–14/15
|
|
||||||
- [EOX Sentinel-2 cloudless](https://s2maps.eu) – tile-by-tile via Script
|
|
||||||
- [Planetiler Hardware Requirements](https://github.com/onthegomap/planetiler)
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
# Session 2026-06-12 – Tile-Server Raster-Architektur
|
|
||||||
|
|
||||||
## Prompt 1
|
|
||||||
Ich habe die eigentliche Ursache gefunden: dein Tile-Server liefert nur Vektor-Tiles (PBF) und keine gerenderten PNG-Styles für Kartographer. Ich teste jetzt einen sofort funktionierenden Raster-Fallback-Pfad, damit Karten in der UI wieder erscheinen. Was müssen wir hier tun damit das geht?
|
|
||||||
|
|
||||||
## Antwort 1
|
|
||||||
Diagnostiziert, dass Martin ohne PNG-Rendering nicht für Kartographer ausreicht. Analyzed:
|
|
||||||
- Martin serviert nur PBF-Vektor-Tiles
|
|
||||||
- Kartographer erwartet PNG (raster) oder MapLibre GL Styles (mit client-side Rendering)
|
|
||||||
- osm.mbtiles ist vorhanden, aber keine Style-Definitionen in /data/styles/
|
|
||||||
|
|
||||||
Empfohlen: Schneller Fallback mit Nginx-Proxy zum OSM.org Upstream ODER lokales Raster-Rendering mit tileserver-gl.
|
|
||||||
|
|
||||||
Dokumentation gelesen: docker-compose.yml, martin.yaml, mediawiki-config.php, api-endpoints.md, REQUIREMENTS.md
|
|
||||||
|
|
||||||
## Prompt 2
|
|
||||||
- Dauerhaft sauber: eigenen Raster-Renderer ergänzen (z. B. tileserver-gl oder openmaptiles-Server) und dieselbe Kartographer-URL-Struktur lokal bedienen. las uns das planen
|
|
||||||
|
|
||||||
## Antwort 2
|
|
||||||
High-Level Plan erarbeitet:
|
|
||||||
- Martin bleibt für Vektor-API und interne Nutzung
|
|
||||||
- Raster-Renderer (tileserver-gl) neu hinzufügen
|
|
||||||
- Reverse Proxy: /osm-intl/{z}/{x}/{y}.png → tileserver-gl
|
|
||||||
- MediaWiki unabhängig von externen Tile-Servern
|
|
||||||
|
|
||||||
Geplant: 6 Arbeitspakete, Abnahmekriterien, Umsetzungsschätzung.
|
|
||||||
|
|
||||||
Alternatives Analyzed: OpenMapTiles Server (overengineered, für euch jetzt nicht nötig), tileserver-gl (optimal für static 2–4×/Year Updates).
|
|
||||||
|
|
||||||
## Prompt 3
|
|
||||||
was ist der unterschied zwischen open map tiles server und martin. Erkläre mir high level warum ich beide brauche was nur der eine und nur der andere kann und warum es besser ist beide zu haben was sind die jeweiligen aufgaben?
|
|
||||||
|
|
||||||
## Antwort 3
|
|
||||||
**Detaillierte Vergleichstabelle erstellt:**
|
|
||||||
|
|
||||||
| Aspekt | Martin | OpenMapTiles Server |
|
|
||||||
|---|---|---|
|
|
||||||
| Kategorie | Tile-Distributer | OSM-Daten-Pipeline |
|
|
||||||
| Eingabe | MBTiles/PMTiles (fertig) | Rohe OSM-Daten oder Shapefile |
|
|
||||||
| Was es macht | Vektor/Raster aus DB auslesen + HTTP servieren | OSM importieren → Vektor-Layer definieren → Rendering-Regeln → Tiles generieren |
|
|
||||||
| Stack-Größe | ~50 MB, single binary | PostGIS + Rendering-Engine + Tile-Generator → GB |
|
|
||||||
|
|
||||||
**Konklusiv:** Martin + tileserver-gl jetzt optimal. OpenMapTiles Server nur nötig wenn Live-OSM-Updates erforderlich (zukünftig, nicht jetzt).
|
|
||||||
|
|
||||||
## Prompt 4
|
|
||||||
ok lass und das im repo als adr festhalten aber wir entscheiden uns für martin und tileservergl für den anfang, wenn ich in dem stack trotzdem stiles und karten anpassen kann und das updaten der karten 2-4 Mal im jahr einfach möglich ist.
|
|
||||||
|
|
||||||
## Antwort 4
|
|
||||||
**Architektur-Entscheidung dokumentiert:**
|
|
||||||
|
|
||||||
1. **ADR-001 erstellt: [docs/adr/001-martin-tileserver-gl-stack.md](../docs/adr/001-martin-tileserver-gl-stack.md)**
|
|
||||||
- Status: Accepted
|
|
||||||
- Decision: Martin (Vektor) + tileserver-gl (Raster PNG)
|
|
||||||
- Rationale: niedrige Komplexität, Style-Flexibilität, 2–4x/Year Update-Zyklus passend
|
|
||||||
- Alternatives analyzed: OpenMapTiles Server (deferred), External proxy (violates ToS)
|
|
||||||
- Future ADRs: ADR-002 (Live OSM Pipeline), ADR-003 (Horizontal Scaling)
|
|
||||||
|
|
||||||
2. **ADR-Template erstellt: [docs/adr/000-template.md](../docs/adr/000-template.md)**
|
|
||||||
- Nygard-Format: Status, Context, Decision, Consequences, Alternatives
|
|
||||||
|
|
||||||
3. **REQUIREMENTS.md aktualisiert**
|
|
||||||
- Architektur-Übersicht hinzugefügt
|
|
||||||
- Link zu ADR-001
|
|
||||||
- Explizit dokumentiert: Styles anpassbar, 2–4x/Year Update-Workflow
|
|
||||||
|
|
||||||
**Files staged & ready for commit:**
|
|
||||||
```
|
|
||||||
A docs/adr/000-template.md
|
|
||||||
A docs/adr/001-martin-tileserver-gl-stack.md
|
|
||||||
M docs/requirements/REQUIREMENTS.md
|
|
||||||
```
|
|
||||||
|
|
@ -1,119 +0,0 @@
|
||||||
# Session 2026-06-13 – Tile-Server vollständig in Betrieb
|
|
||||||
|
|
||||||
### Prompt 1
|
|
||||||
Schau jetzt nochmal auf alles drauf und versuche die aktuellen Probleme zu lösen! Ich habe jetzt einen neuen Proxy Caddy unter rd13_system_proxy als repo wenn du es nötig hast kannst du diesen auch in einem git workflow nach belieben anpassen damit das mit dem tile server funktioniert. Je mehr allerdings in dem Tile repo und dem dafür vorgesehenen docker stack gelöst werden kann desto besser.
|
|
||||||
|
|
||||||
### Antwort 1
|
|
||||||
Stack vollständig verifiziert: Martin (healthy), tileserver-gl (healthy), Caddy aktiv.
|
|
||||||
Smoke-Test bestanden: Zoom 0/5/10/14 HTTP 200 PNG, PBF 200, /health OK.
|
|
||||||
PROJECT_CONTEXT aktualisiert, committed: `2765bb9`
|
|
||||||
|
|
||||||
### Prompt 2
|
|
||||||
Geh nochmal ins MediaWiki und überprüfe die config und auch ob die config geladen ist.
|
|
||||||
|
|
||||||
### Antwort 2
|
|
||||||
Problem gefunden: `wikidata/LocalSettings.php` (der echte Mount) zeigte noch auf `tile.openstreetmap.org`.
|
|
||||||
Fix: auf `https://tiles.rd13server.de/styles` + `osm-intl` umgestellt.
|
|
||||||
Zweites Problem: Font-Fehler bei Zoom ≥10 – `glyphs`-URL war relativ, tileserver-gl konnte Fonts nicht laden.
|
|
||||||
Fix: `glyphs` auf absolute URL `http://192.168.178.6:9983/fonts/{fontstack}/{range}.pbf`.
|
|
||||||
Commits: `9081ed9` (tile-server), `627a1b1` (mediawiki)
|
|
||||||
|
|
||||||
### Prompt 3
|
|
||||||
ok sieht gut aus, allerdings sehe ich nur orte und gebäude. Ich hätte gerne eine vollständige openstreetmap karte mit allen wanderwegen und bekannten punkten.
|
|
||||||
|
|
||||||
### Antwort 3
|
|
||||||
Alten minimalen Style (15 Layer) durch OSM Bright GL (128 Layer, offizieller OpenMapTiles-Referenz-Style) ersetzt.
|
|
||||||
Sprites heruntergeladen (4 Dateien: osm-bright.json/png + @2x), Sprite-Pfad-Problem gelöst.
|
|
||||||
Zoom 12 München: 2.9 KB → 32 KB (11× mehr Inhalt). Commit: `4268b41`
|
|
||||||
|
|
||||||
### Prompt 4
|
|
||||||
Ist hier jetzt die ganze Welt verfügbar offline schon auf meinem Server oder werden Daten noch nachgeladen?
|
|
||||||
|
|
||||||
### Antwort 4
|
|
||||||
Verifiziert: osm.mbtiles = OpenFreeMap, 95 GB, Bounds -180/-85 bis +180/+85 (kompletter Planet), z0–14.
|
|
||||||
Keine externen URLs im Style. Vollständig offline.
|
|
||||||
|
|
||||||
### Prompt 5
|
|
||||||
Wenn das einfach geht hätte ich gerne noch Deutschland oder Europa bis Zoom Level 16. Ebenso will ich Satellitenkarten für den ganzen Planeten, was benötigen wir dafür und wie viel SSD Platz bräuchten wir dafür?
|
|
||||||
|
|
||||||
### Antwort 5
|
|
||||||
Analyse: z16 Europa ~60–90 GB, Satellit z0–11 ~38 GB, z12 ~140 GB.
|
|
||||||
Hardware-Anforderungen dokumentiert.
|
|
||||||
|
|
||||||
### Prompt 6
|
|
||||||
Für das Zoom Level 16 Europa muss ich diese unbedingt selbst bauen oder gibt's die wieder fertig zum download? Selbst bauen will ich ausschließen und im Repo festhalten dass das auf der aktuellen HW nicht möglich ist. Das gilt auch für die Satellitendaten.
|
|
||||||
|
|
||||||
### Antwort 6
|
|
||||||
Recherche: Kein Pre-Built für Europa/DE z16 verfügbar (OpenFreeMap, Protomaps, Geofabrik alle nur bis z14).
|
|
||||||
Kein Planet-Satellit-MBTiles als Download verfügbar.
|
|
||||||
ADR-002 erstellt: Hardware-Constraint dauerhaft dokumentiert, kein Agent startet Planetiler-Build.
|
|
||||||
Commit: `c47f478`
|
|
||||||
|
|
||||||
### Prompt 7
|
|
||||||
Ich könnte die z16 auf meinem Host-Rechner bauen und dann transferieren? Da habe ich genug Ressourcen zur Verfügung. Und die Satellitenkarten stückweise runterladen klingt gut!
|
|
||||||
|
|
||||||
### Antwort 7
|
|
||||||
`scripts/build-host.sh` erstellt: Docker-basierter Planetiler-Build (germany/austria/europe/planet),
|
|
||||||
mit RAM-Profilen, Validierung und rsync-Transfer auf Server.
|
|
||||||
Satellit-Download via nohup gestartet – aber VS Code Sessions brachen ab.
|
|
||||||
|
|
||||||
### Prompt 8
|
|
||||||
Jedes Mal wenn du versuchst den Download zu starten brechen die VS Code Remote Sessions ab. Sollten wir das vielleicht etwas ordentlicher aufsetzen? Vielleicht ein Python Script das sicher aus einem Container ausgeführt wird?
|
|
||||||
|
|
||||||
### Antwort 8
|
|
||||||
Ursache: `nohup`/`&` in Fish-Shell + VS Code Remote = instabile Session.
|
|
||||||
Lösung: eigenständiger Docker-Container für Downloads.
|
|
||||||
`docker-compose.download.yml` erstellt, Script mit `flush=True` robuster gemacht.
|
|
||||||
Überreste bereinigt: satellite.mbtiles (4 KB stub), satellite.mbtiles-shm/wal, satellite.log.
|
|
||||||
|
|
||||||
### Prompt 11
|
|
||||||
Lass uns gleich planet bauen wenn das geht. Und achte wieder auf Robustheit und Ressourcenverbrauch. Du kannst bis zu 12 CPUs und 32 GB RAM verwenden auf meinem Host-Rechner.
|
|
||||||
|
|
||||||
### Antwort 11
|
|
||||||
Disk-Analyse: Server hat 555 GB frei, Planet z16 bräuchte ~900 GB auf dem Host → nicht empfohlen.
|
|
||||||
docker-compose.build.yml robuster gemacht: Volumes aufgeteilt (output/sources/tmp getrennt), `--nodemap-type=sortedtable` für weniger RAM, G1GC-JVM-Flags, Disk-Anforderungen in Kommentaren.
|
|
||||||
|
|
||||||
### Prompt 12
|
|
||||||
Ok dann lass uns das nur für Europa in z16 bauen. Wie viel wären es dann?
|
|
||||||
|
|
||||||
### Antwort 12
|
|
||||||
Europa z16: ~25 GB Sources + ~150 GB Temp + ~80 GB Output = ~280 GB auf Host. Server: +80 GB (555 GB frei → kein Problem). Buildzeit: ~8–12h mit 12 CPUs.
|
|
||||||
|
|
||||||
### Prompt 13
|
|
||||||
Ok ja so bauen wir es!
|
|
||||||
|
|
||||||
### Antwort 13
|
|
||||||
docker-compose.build.yml committed. Startbefehl für Host:
|
|
||||||
```bash
|
|
||||||
AREA=europe MAX_ZOOM=16 RAM=28g BUILD_CPUS=12 BUILD_MEM=30g \
|
|
||||||
docker compose -f docker-compose.build.yml up
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Antwort 10
|
|
||||||
OOM-Ursache identifiziert: Script submittete alle 5,5 Mio Futures gleichzeitig in eine Liste → Memory-Spike beim Aufbau.
|
|
||||||
Fix: Bounded Queue mit `threading.Semaphore(THREADS * 4)` – max 64 Futures gleichzeitig im Speicher.
|
|
||||||
Threads auf 16 erhöht, RAM-Limit auf 2 GB. Alte korrupte MBTiles entfernt, neu gestartet.
|
|
||||||
|
|
||||||
Ergebnis:
|
|
||||||
```
|
|
||||||
CPU: 18% RAM: 44 MiB / 2 GiB Threads: 16
|
|
||||||
data/satellite.mbtiles wächst von 4KB → 5.4MB → ...
|
|
||||||
```
|
|
||||||
Container läuft stabil ohne OOM.
|
|
||||||
|
|
||||||
### Antwort 9
|
|
||||||
Service aus `docker-compose.yml` entfernt.
|
|
||||||
`docker-compose.download.yml` als eigenständiger Stack angelegt.
|
|
||||||
```
|
|
||||||
# Starten:
|
|
||||||
docker compose -f docker-compose.download.yml up
|
|
||||||
|
|
||||||
# Status:
|
|
||||||
docker compose -f docker-compose.download.yml logs -f
|
|
||||||
|
|
||||||
# Pause/Resume:
|
|
||||||
docker compose -f docker-compose.download.yml stop
|
|
||||||
docker compose -f docker-compose.download.yml up
|
|
||||||
```
|
|
||||||
ADMIN.md mit Satelliten-Download-Anleitung ergänzt.
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
# PROJECT_CONTEXT – rd13_tile_server
|
|
||||||
|
|
||||||
**Letzte Aktualisierung:** 2026-06-13 – Satellit-Download läuft (~372 MB, stabil). Europa z16 Build-Container vorbereitet für Host-Rechner.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Projektziel
|
|
||||||
|
|
||||||
Selbst gehosteter Tile Server für MediaWiki (Kartographer), Nextcloud, Home Assistant.
|
|
||||||
**Stack:** Martin (Vektor-API) + tileserver-gl (Raster PNG) + Caddy (Reverse Proxy).
|
|
||||||
Tile-Updates manuell 2–4×/Jahr; Styles anpassbar.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Stack (Architektur ADR-001)
|
|
||||||
|
|
||||||
- **Vektor-API:** `ghcr.io/maplibre/martin:latest` (Port 9982 → `/osm/{z}/{x}/{y}`)
|
|
||||||
- **Raster-Renderer:** `maptiler/tileserver-gl` (Port 9983 → `/styles/osm-intl/{z}/{x}/{y}.png`)
|
|
||||||
- **Style:** OSM Bright GL (128 Layer, Wanderwege, POIs, vollständige Weltkarte)
|
|
||||||
- **Proxy:** Caddy (`rd13_system_proxy`) – SSL, Routing `/styles/` → 9983, rest → 9982
|
|
||||||
- **Konfiguration:** `config/tileserver.json`, `config/styles/osm-intl.json`
|
|
||||||
- **Daten:** `data/osm.mbtiles` (95 GB, Planet z0–14), `data/sprites/`, `data/fonts/`
|
|
||||||
- **Satellit:** `docker-compose.download.yml` → `data/satellite.mbtiles` (~38 GB, z0–11, noch nicht gestartet)
|
|
||||||
- **Git Remote:** `ssh://git@192.168.178.6:2222/cschulz/rd13_tile_server.git`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architektur-Decision: Martin + tileserver-gl
|
|
||||||
|
|
||||||
**Rationale:** [siehe ADR-001](../../docs/adr/001-martin-tileserver-gl-stack.md)
|
|
||||||
|
|
||||||
| Komponente | Rolle | Input | Output |
|
|
||||||
|---|---|---|---|
|
|
||||||
| Martin | Vektor-Tile-API | osm.mbtiles | `/osm/{z}/{x}/{y}.pbf` |
|
|
||||||
| tileserver-gl | Raster-Renderer | Martin PBF + Styles | `/osm-intl/{z}/{x}/{y}.png` |
|
|
||||||
| NPM | Proxy + Rate Limit | Requests | HTTPS mit Cache-Headers |
|
|
||||||
|
|
||||||
**Kartographer-URL bleibt gleich:**
|
|
||||||
- `$wgKartographerMapServer = 'https://tiles.rd13server.de'`
|
|
||||||
- Style `osm-intl` (Raster)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Aktueller Zustand
|
|
||||||
|
|
||||||
### Laufende Services
|
|
||||||
- Martin-Container: **laeuft** und ist **healthy**
|
|
||||||
- WebUI: **aktiviert** ueber `--webui enable-for-all`
|
|
||||||
|
|
||||||
### Vorhandene Daten in `/data/`
|
|
||||||
| Datei/Ordner | Status |
|
|
||||||
|---|---|
|
|
||||||
| `osm.mbtiles` | ✅ wird von Martin erkannt (Source `osm`) |
|
|
||||||
| `fonts/` | ✅ installiert |
|
|
||||||
| `styles/` | ✅ vorhanden |
|
|
||||||
| `satellite.mbtiles` | ❌ noch nicht heruntergeladen |
|
|
||||||
|
|
||||||
### Git-Stand
|
|
||||||
- Branch: `main`
|
|
||||||
- Letzter Commit: `46ac204` – tileserver-gl operational, config in config/
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Aktueller Zustand (2026-06-13) – VOLLSTÄNDIG IN BETRIEB ✅
|
|
||||||
|
|
||||||
| Endpunkt | Status | Antwort |
|
|
||||||
|---|---|---|
|
|
||||||
| `https://tiles.rd13server.de/styles/osm-intl/{z}/{x}/{y}.png` | ✅ 200 | PNG 256×256 |
|
|
||||||
| `https://tiles.rd13server.de/osm/{z}/{x}/{y}` (PBF) | ✅ 200 | application/x-protobuf |
|
|
||||||
| `https://tiles.rd13server.de/health` | ✅ 200 | OK |
|
|
||||||
| `rd13_tileserver` Container | ✅ healthy | Port 9983 |
|
|
||||||
| `rd13_martin` Container | ✅ healthy | Port 9982 |
|
|
||||||
| Caddy Proxy (`rd13_system_proxy`) | ✅ aktiv | server: Caddy |
|
|
||||||
|
|
||||||
**MediaWiki Kartographer Config:**
|
|
||||||
- `$wgKartographerMapServer = 'https://tiles.rd13server.de/styles'`
|
|
||||||
- `$wgKartographerDfltStyle = 'osm-intl'`
|
|
||||||
- → Request-URL: `https://tiles.rd13server.de/styles/osm-intl/{z}/{x}/{y}.png` ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Nächste Schritte
|
|
||||||
|
|
||||||
|
|
||||||
## Offene Aufgaben
|
|
||||||
|
|
||||||
## Bekannte Fallstricke
|
|
||||||
|
|
||||||
- `data/tmp/` und `data/sources/` werden von Docker als `root` erstellt → `sudo rm -rf` nötig
|
|
||||||
- Planetiler braucht sehr viel Disk (87 GB sources + 264 GB tmp + ~70 GB output = ~420 GB)
|
|
||||||
→ **Nicht mehr nötig**, wir nutzen OpenFreeMap MBTiles direkt
|
|
||||||
- Fish Shell unterstützt kein heredoc `<< 'EOF'` → Python `open().write()` oder `tee` verwenden
|
|
||||||
- Download von OpenFreeMap: `wget --continue` für Resume-Support bei Abbruch
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Erledigte Aufgaben
|
|
||||||
|
|
||||||
- [x] Git-Repo initialisiert und auf Forgejo gepusht
|
|
||||||
- [x] Martin WebUI aktiviert (`--webui enable-for-all`)
|
|
||||||
- [x] Endpunkte verifiziert (`/health`, `/catalog`, Root 200)
|
|
||||||
- [x] MediaWiki-Kartographer Doku + LocalSettings konfiguriert
|
|
||||||
- [x] ADR-001: Martin + tileserver-gl Stack-Entscheidung dokumentiert
|
|
||||||
- [x] **tileserver-gl** Service in docker-compose.yml (Port 9983, `maptiler/tileserver-gl`)
|
|
||||||
- [x] `config/tileserver.json` – Service-Konfiguration (MBTiles + Styles + Fonts)
|
|
||||||
- [x] `config/styles/osm-intl.json` – MapLibre GL Style für Raster-Rendering
|
|
||||||
- [x] Caddy-Routing: `/styles/osm-intl/*` → Port 9983, rest → Port 9982
|
|
||||||
- [x] **End-to-End verifiziert:** PNG-Tiles 200 bei Zoom 0/5/10/14
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Offene Aufgaben
|
|
||||||
|
|
||||||
- [ ] **MediaWiki in Browser testen** – mapframe/maplink auf einer Wiki-Seite
|
|
||||||
- [ ] **REQ-002 Rate Limiting** – Caddy-seitig absichern (rd13_system_proxy)
|
|
||||||
- [ ] **REQ-002 Rate Limiting** – NPM Advanced Config für `tiles.rd13server.de`
|
|
||||||
- [ ] NPM Proxy-Host für `tiles.rd13server.de` anlegen (manuell im NPM UI)
|
|
||||||
- [ ] fail2ban optional konfigurieren (REQ-002 Schicht 3)
|
|
||||||
- [ ] Satellit-Download (optional, REQ-005)
|
|
||||||
- [ ] Martin mit Satellit-Daten testen
|
|
||||||
|
|
@ -1,23 +1,6 @@
|
||||||
# Anforderungen – rd13_tile_server
|
# Anforderungen – rd13_tile_server
|
||||||
|
|
||||||
Letzte Aktualisierung: 2026-06-13
|
Letzte Aktualisierung: 2026-06-10
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architektur-Entscheidung
|
|
||||||
|
|
||||||
**Stack:** Martin (Vektor-API) + tileserver-gl (Raster-Renderer)
|
|
||||||
|
|
||||||
Rationale: [siehe ADR-001](../adr/001-martin-tileserver-gl-stack.md)
|
|
||||||
|
|
||||||
- Martin: Vektor-Tiles (PBF) – API-Foundation für zukünftige MapLibre GL Integration
|
|
||||||
- tileserver-gl: PNG-Rendering – Kartographer + externe Clients (Home Assistant, Nextcloud)
|
|
||||||
- Tile-Updates: manuell 2–4×/Jahr (nicht live)
|
|
||||||
- Styles: Anpassbar über JSON-Style-Definitionen in `config/styles/`
|
|
||||||
|
|
||||||
**⛔ Hardware-Einschränkung (dauerhaft):**
|
|
||||||
Kein Planetiler-Self-Build auf dieser Hardware. Kein Pre-Built für Europa/DE z16 verfügbar.
|
|
||||||
→ Begründung: [ADR-002](../adr/002-no-highzoom-no-satellite-build.md)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -29,7 +12,7 @@ Der Tile Server muss über HTTPS unter einer öffentlichen Domain erreichbar sei
|
||||||
damit externe Dienste (MediaWiki, Home Assistant, Nextcloud) Karten laden können.
|
damit externe Dienste (MediaWiki, Home Assistant, Nextcloud) Karten laden können.
|
||||||
|
|
||||||
**Akzeptanzkriterien:**
|
**Akzeptanzkriterien:**
|
||||||
- Erreichbar unter `https://tiles.rd13server.de`
|
- Erreichbar unter `https://tile.rd13server.de`
|
||||||
- SSL-Terminierung via NPM
|
- SSL-Terminierung via NPM
|
||||||
- Health-Endpunkt antwortet mit HTTP 200
|
- Health-Endpunkt antwortet mit HTTP 200
|
||||||
|
|
||||||
|
|
@ -39,7 +22,7 @@ damit externe Dienste (MediaWiki, Home Assistant, Nextcloud) Karten laden könne
|
||||||
|
|
||||||
**Status:** 🔴 offen – Implementierung erforderlich vor Live-Gang
|
**Status:** 🔴 offen – Implementierung erforderlich vor Live-Gang
|
||||||
|
|
||||||
Da der Server unter `https://tiles.rd13server.de` öffentlich erreichbar ist, muss
|
Da der Server unter `https://tile.rd13server.de` öffentlich erreichbar ist, muss
|
||||||
er gegen unautorisierten Massenkonsum und DoS-Angriffe geschützt werden.
|
er gegen unautorisierten Massenkonsum und DoS-Angriffe geschützt werden.
|
||||||
|
|
||||||
### Anforderungen
|
### Anforderungen
|
||||||
|
|
@ -90,7 +73,7 @@ Da NPM keinen bedingten Block pro Location direkt unterstuetzt, wird ein
|
||||||
zweiter Proxy-Host fuer interne Endpunkte empfohlen:
|
zweiter Proxy-Host fuer interne Endpunkte empfohlen:
|
||||||
|
|
||||||
```
|
```
|
||||||
Oeffentlicher Proxy-Host: tiles.rd13server.de -> http://HOST:9982
|
Oeffentlicher Proxy-Host: tile.rd13server.de -> http://HOST:9982
|
||||||
→ nur Tile-Pfade freigeben, alle anderen 403
|
→ nur Tile-Pfade freigeben, alle anderen 403
|
||||||
→ Rate Limiting aktiv
|
→ Rate Limiting aktiv
|
||||||
|
|
||||||
|
|
@ -123,10 +106,10 @@ bantime = 3600
|
||||||
|
|
||||||
### Reihenfolge der Umsetzung
|
### Reihenfolge der Umsetzung
|
||||||
|
|
||||||
1. NPM Proxy-Host fuer `tiles.rd13server.de` anlegen (falls noch nicht vorhanden)
|
1. NPM Proxy-Host fuer `tile.rd13server.de` anlegen (falls noch nicht vorhanden)
|
||||||
2. Rate-Limiting-Block in NPM Advanced Config eintragen
|
2. Rate-Limiting-Block in NPM Advanced Config eintragen
|
||||||
3. NPM Access List „LAN" anlegen und auf `/` + `/catalog` anwenden
|
3. NPM Access List „LAN" anlegen und auf `/` + `/catalog` anwenden
|
||||||
4. Test: `ab -n 200 -c 10 https://tiles.rd13server.de/osm/10/0/0` → 429 nach Burst
|
4. Test: `ab -n 200 -c 10 https://tile.rd13server.de/osm/10/0/0` → 429 nach Burst
|
||||||
5. fail2ban optional installieren und konfigurieren
|
5. fail2ban optional installieren und konfigurieren
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -148,7 +131,7 @@ die Last auf den Server zu reduzieren.
|
||||||
|
|
||||||
**Status:** ✅ umgesetzt (LocalSettings konfiguriert)
|
**Status:** ✅ umgesetzt (LocalSettings konfiguriert)
|
||||||
|
|
||||||
Kartographer nutzt `https://tiles.rd13server.de` als Tile-Server.
|
Kartographer nutzt `https://tile.rd13server.de` als Tile-Server.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -157,13 +140,4 @@ Kartographer nutzt `https://tiles.rd13server.de` als Tile-Server.
|
||||||
**Status:** 📋 dokumentiert, nicht getestet
|
**Status:** 📋 dokumentiert, nicht getestet
|
||||||
|
|
||||||
Satellit-Tiles als Raster-Layer in HA-Map-Card einbindbar.
|
Satellit-Tiles als Raster-Layer in HA-Map-Card einbindbar.
|
||||||
|
Wartet auf `satellite.mbtiles` Download.
|
||||||
**Satellit-Download-Entscheidung (2026-06-13):**
|
|
||||||
- Kein Pre-Built Planet-Satellit-MBTiles verfügbar → [ADR-002](../adr/002-no-highzoom-no-satellite-build.md)
|
|
||||||
- Download z0–11 (~38 GB, ~24h) via `scripts/download-satellite.py` möglich wenn gewünscht
|
|
||||||
- z12+ auf dieser Hardware nicht praktikabel (140 GB+, 3–5 Tage)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Satellit z0-11 starten (optional, bei Bedarf):
|
|
||||||
SAT_MAX_ZOOM=11 python3 scripts/download-satellite.py data/satellite.mbtiles
|
|
||||||
```
|
|
||||||
|
|
|
||||||
|
|
@ -132,24 +132,3 @@ Relevante Outputs:
|
||||||
5 files changed, 114 insertions(+), 44 deletions(-)
|
5 files changed, 114 insertions(+), 44 deletions(-)
|
||||||
M docs/mediawiki-config.php
|
M docs/mediawiki-config.php
|
||||||
```
|
```
|
||||||
|
|
||||||
### Prompt 7
|
|
||||||
«media wiki sollte aktuell sein, aber commite alle änderungen in diesem repo um die änderung abzuschließen.»
|
|
||||||
|
|
||||||
### Antwort 7
|
|
||||||
Der Arbeitsbaum wurde auf die vereinheitlichten Hostnamen umgestellt, die Projektkontext- und Requirements-Dateien wurden aktualisiert und danach zur Vorbereitung des Commits geprüft.
|
|
||||||
|
|
||||||
Ausgefuehrte Kommandos:
|
|
||||||
```bash
|
|
||||||
git status --short
|
|
||||||
ls /mnt/services-data/rd13_tile_server/history/prompts
|
|
||||||
git diff -- docs/requirements/REQUIREMENTS.md history/summary/PROJECT_CONTEXT.md
|
|
||||||
```
|
|
||||||
|
|
||||||
Relevante Outputs:
|
|
||||||
```text
|
|
||||||
M docs/requirements/REQUIREMENTS.md
|
|
||||||
M history/summary/PROJECT_CONTEXT.md
|
|
||||||
2026-06-03_tile-server-setup_session.md
|
|
||||||
2026-06-10_tile-mediawiki-integration_session.md
|
|
||||||
```
|
|
||||||
100
history/summary/PROJECT_CONTEXT.md
Normal file
100
history/summary/PROJECT_CONTEXT.md
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
# PROJECT_CONTEXT – rd13_tile_server
|
||||||
|
|
||||||
|
**Letzte Aktualisierung:** 2026-06-10 – Martin laeuft healthy, WebUI aktiv, MediaWiki integriert, Rate-Limiting-Anforderung aufgenommen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Projektziel
|
||||||
|
|
||||||
|
Selbst gehosteter Tile Server auf Basis von **Martin** (Rust), der für MediaWiki,
|
||||||
|
Nextcloud, Home Assistant und andere Dienste Vektorkarten bereitstellt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
- **Tile Server:** `ghcr.io/maplibre/martin:latest`
|
||||||
|
- **Port:** 9982 extern → 3000 intern
|
||||||
|
- **Proxy:** NPM (Nginx Proxy Manager) extern – kein nginx-Sidecar
|
||||||
|
- **Daten:** MBTiles/PMTiles in `/data/`
|
||||||
|
- **Git Remote:** `ssh://git@192.168.178.6:2222/cschulz/rd13_tile_server.git`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Aktueller Zustand
|
||||||
|
|
||||||
|
### Laufende Services
|
||||||
|
- Martin-Container: **laeuft** und ist **healthy**
|
||||||
|
- WebUI: **aktiviert** ueber `--webui enable-for-all`
|
||||||
|
|
||||||
|
### Vorhandene Daten in `/data/`
|
||||||
|
| Datei/Ordner | Status |
|
||||||
|
|---|---|
|
||||||
|
| `osm.mbtiles` | ✅ wird von Martin erkannt (Source `osm`) |
|
||||||
|
| `fonts/` | ✅ installiert |
|
||||||
|
| `styles/` | ✅ vorhanden |
|
||||||
|
| `satellite.mbtiles` | ❌ noch nicht heruntergeladen |
|
||||||
|
|
||||||
|
### Git-Stand
|
||||||
|
- Branch: `main`
|
||||||
|
- Letzter Commit: `0a5f6cd` - WebUI aktiviert und MediaWiki-Integration vorbereitet
|
||||||
|
- Noch offen (lokal): `docs/mediawiki-config.php`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nächste Schritte (fuer naechsten Agenten)
|
||||||
|
|
||||||
|
1. **REQ-002 Rate Limiting im NPM UI eintragen** (manuell):
|
||||||
|
- Proxy-Host: `https://tile.rd13server.de` → `http://HOST:9982`
|
||||||
|
- Advanced Config: Rate-Limiting-Block aus `docs/requirements/REQUIREMENTS.md` einfügen
|
||||||
|
- NPM Access List „LAN" für `/` und `/catalog` anlegen
|
||||||
|
|
||||||
|
2. **Satellit-Download starten** (optional, ~10 GB, Zoom 0–10):
|
||||||
|
```bash
|
||||||
|
tmux new-session -d -s rd13-sat -c /mnt/services-data/rd13_tile_server \
|
||||||
|
'python3 scripts/download-satellite.py data/satellite.mbtiles 2>&1 | tee logs/satellite.log'
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **NPM konfigurieren** (manuell im NPM UI):
|
||||||
|
- Proxy Host: `http://HOST:9982`
|
||||||
|
- Advanced Config: `add_header Cache-Control "public, max-age=86400, stale-while-revalidate=3600" always;`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bekannte Fallstricke
|
||||||
|
|
||||||
|
- `data/tmp/` und `data/sources/` werden von Docker als `root` erstellt → `sudo rm -rf` nötig
|
||||||
|
- Planetiler braucht sehr viel Disk (87 GB sources + 264 GB tmp + ~70 GB output = ~420 GB)
|
||||||
|
→ **Nicht mehr nötig**, wir nutzen OpenFreeMap MBTiles direkt
|
||||||
|
- Fish Shell unterstützt kein heredoc `<< 'EOF'` → Python `open().write()` oder `tee` verwenden
|
||||||
|
- Download von OpenFreeMap: `wget --continue` für Resume-Support bei Abbruch
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Erledigte Aufgaben
|
||||||
|
|
||||||
|
- [x] Git-Repo initialisiert und auf Forgejo gepusht
|
||||||
|
- [x] Migration TileServer-GL → Martin
|
||||||
|
- [x] nginx-Sidecar entfernt (NPM extern)
|
||||||
|
- [x] Port auf 9982 geändert
|
||||||
|
- [x] copilot-instructions auf aktuelles Template aktualisiert
|
||||||
|
- [x] download-data.sh + download-satellite.py erstellt
|
||||||
|
- [x] History-System (post-commit Hook + _session.md Konvention) in rd13_copilot_setup implementiert
|
||||||
|
- [x] Docs für MediaWiki, Nextcloud, Home Assistant erstellt
|
||||||
|
- [x] Planet-MBTiles Download gestartet (OpenFreeMap, 94 GB)
|
||||||
|
- [x] Martin WebUI aktiviert (`--webui enable-for-all`)
|
||||||
|
- [x] Endpunkte verifiziert (`/health`, `/catalog`, Root 200)
|
||||||
|
- [x] MediaWiki-Kartographer Doku in `docs/mediawiki-config.php` erweitert
|
||||||
|
- [x] MediaWiki-Repo auf Martin umgestellt und committed
|
||||||
|
- [x] Rate-Limiting-Anforderungen in `docs/requirements/REQUIREMENTS.md` aufgenommen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Offene Aufgaben
|
||||||
|
|
||||||
|
- [ ] **REQ-002 Rate Limiting** – NPM Advanced Config für `tile.rd13server.de` eintragen (Details: `docs/requirements/REQUIREMENTS.md`)
|
||||||
|
- [ ] NPM Proxy-Host für `tile.rd13server.de` anlegen (manuell im NPM UI)
|
||||||
|
- [ ] fail2ban optional konfigurieren (REQ-002 Schicht 3)
|
||||||
|
- [ ] Satellit-Download (optional, REQ-005)
|
||||||
|
- [ ] Hook-Verteilung auf alle Repos (install-hooks.sh)
|
||||||
|
- [ ] Martin mit Satellit-Daten testen
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
# =============================================================================
|
|
||||||
# build-host.sh -- OSM Vektor-Tiles auf Host-Rechner bauen + auf Server deployen
|
|
||||||
#
|
|
||||||
# Dieses Script läuft auf dem HOST-RECHNER (nicht auf dem Server).
|
|
||||||
# Voraussetzung: Docker Desktop (macOS/Windows) oder Docker (Linux)
|
|
||||||
#
|
|
||||||
# Verwendung:
|
|
||||||
# ./scripts/build-host.sh [germany|europe|planet] [SERVER_USER@SERVER_HOST]
|
|
||||||
#
|
|
||||||
# Beispiele:
|
|
||||||
# ./scripts/build-host.sh germany rd13server@192.168.178.6
|
|
||||||
# ./scripts/build-host.sh europe rd13server@192.168.178.6
|
|
||||||
#
|
|
||||||
# Das fertige MBTiles wird per rsync auf den Server übertragen und Martin
|
|
||||||
# automatisch neu gestartet.
|
|
||||||
#
|
|
||||||
# Hardware-Anforderungen:
|
|
||||||
# germany: ≥ 8 GB RAM, ≥ 30 GB freier Disk, ~2h
|
|
||||||
# europe: ≥ 16 GB RAM, ≥ 200 GB freier Disk, ~8-12h
|
|
||||||
# planet: ≥ 32 GB RAM, ≥ 500 GB freier Disk, ~24h
|
|
||||||
# =============================================================================
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
AREA="${1:-germany}"
|
|
||||||
REMOTE="${2:-}"
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
BUILD_DIR="${SCRIPT_DIR}/../data/build"
|
|
||||||
OUTPUT_FILE="${BUILD_DIR}/${AREA}.mbtiles"
|
|
||||||
|
|
||||||
# ── RAM-Profil ───────────────────────────────────────────────────────────────
|
|
||||||
case "$AREA" in
|
|
||||||
germany) RAM="8g" ;;
|
|
||||||
austria) RAM="4g" ;;
|
|
||||||
europe) RAM="16g" ;;
|
|
||||||
planet) RAM="32g" ;;
|
|
||||||
*)
|
|
||||||
echo "Unbekannte Region: $AREA"
|
|
||||||
echo "Verfügbar: germany | austria | europe | planet"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
mkdir -p "$BUILD_DIR"
|
|
||||||
|
|
||||||
echo "================================================================"
|
|
||||||
echo " rd13 Tile-Build | Region: $AREA | RAM: $RAM | $(date)"
|
|
||||||
echo " Output: $OUTPUT_FILE"
|
|
||||||
echo "================================================================"
|
|
||||||
|
|
||||||
# ── 1. Planetiler bauen ──────────────────────────────────────────────────────
|
|
||||||
echo ""
|
|
||||||
echo "[1/3] Starte Planetiler via Docker..."
|
|
||||||
echo " (OSM-Daten werden automatisch von Geofabrik heruntergeladen)"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
docker run --rm \
|
|
||||||
-v "${BUILD_DIR}:/data" \
|
|
||||||
-e JAVA_TOOL_OPTIONS="-Xmx${RAM}" \
|
|
||||||
ghcr.io/onthegomap/planetiler:latest \
|
|
||||||
--download \
|
|
||||||
--area="${AREA}" \
|
|
||||||
--output="/data/${AREA}.mbtiles" \
|
|
||||||
--maxzoom=16 \
|
|
||||||
--force
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "[1/3] Build fertig: $(ls -lh "$OUTPUT_FILE" | awk '{print $5}')"
|
|
||||||
|
|
||||||
# ── 2. Validieren ────────────────────────────────────────────────────────────
|
|
||||||
echo "[2/3] Validiere MBTiles..."
|
|
||||||
python3 - <<PYEOF
|
|
||||||
import sqlite3, sys
|
|
||||||
conn = sqlite3.connect("${OUTPUT_FILE}")
|
|
||||||
meta = dict(conn.execute("SELECT name, value FROM metadata").fetchall())
|
|
||||||
maxzoom = meta.get("maxzoom", "?")
|
|
||||||
bounds = meta.get("bounds", "?")
|
|
||||||
count = conn.execute("SELECT COUNT(*) FROM tiles").fetchone()[0]
|
|
||||||
print(f" Name: {meta.get('name','?')}")
|
|
||||||
print(f" MaxZoom: {maxzoom}")
|
|
||||||
print(f" Bounds: {bounds}")
|
|
||||||
print(f" Tiles: {count:,}")
|
|
||||||
if int(maxzoom) < 14:
|
|
||||||
print("FEHLER: MaxZoom < 14 – Build unvollständig?")
|
|
||||||
sys.exit(1)
|
|
||||||
conn.close()
|
|
||||||
print(" ✓ Validierung OK")
|
|
||||||
PYEOF
|
|
||||||
|
|
||||||
# ── 3. Transfer auf Server ───────────────────────────────────────────────────
|
|
||||||
if [[ -n "$REMOTE" ]]; then
|
|
||||||
REMOTE_PATH="/mnt/services-data/rd13_tile_server/data/osm-${AREA}.mbtiles"
|
|
||||||
echo ""
|
|
||||||
echo "[3/3] Übertrage nach ${REMOTE}:${REMOTE_PATH}..."
|
|
||||||
echo " (rsync – bricht/fortsetzt bei Verbindungsunterbrechung)"
|
|
||||||
rsync -avh --progress \
|
|
||||||
--partial --partial-dir="${BUILD_DIR}/.rsync-partial" \
|
|
||||||
"${OUTPUT_FILE}" \
|
|
||||||
"${REMOTE}:${REMOTE_PATH}"
|
|
||||||
echo ""
|
|
||||||
echo "[3/3] Starte Martin auf Server neu..."
|
|
||||||
ssh "${REMOTE}" "cd /mnt/services-data/rd13_tile_server && docker compose restart martin"
|
|
||||||
echo ""
|
|
||||||
echo "✓ Fertig! Neue Source verfügbar unter:"
|
|
||||||
echo " https://tiles.rd13server.de/osm-${AREA}"
|
|
||||||
echo ""
|
|
||||||
echo " Füge in config/styles/osm-intl.json eine zweite Source hinzu:"
|
|
||||||
echo " \"osm-${AREA}\": { \"type\": \"vector\", \"url\": \"mbtiles://{osm-${AREA}}\" }"
|
|
||||||
else
|
|
||||||
echo ""
|
|
||||||
echo "[3/3] Kein Remote angegeben – Transfer übersprungen."
|
|
||||||
echo " MBTiles liegt unter: ${OUTPUT_FILE}"
|
|
||||||
echo ""
|
|
||||||
echo " Manueller Transfer:"
|
|
||||||
echo " rsync -avh --progress ${OUTPUT_FILE} USER@SERVER:/mnt/services-data/rd13_tile_server/data/osm-${AREA}.mbtiles"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "================================================================"
|
|
||||||
echo " Build abgeschlossen: $(date)"
|
|
||||||
echo "================================================================"
|
|
||||||
|
|
@ -74,41 +74,30 @@ def do_tile(conn, z, x, y):
|
||||||
stats["err"] += 1
|
stats["err"] += 1
|
||||||
|
|
||||||
|
|
||||||
def log(msg):
|
|
||||||
print(msg, flush=True)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
total = sum(4 ** z for z in range(MAX_ZOOM + 1))
|
total = sum(4 ** z for z in range(MAX_ZOOM + 1))
|
||||||
log("[Sat] Output: %s" % OUTPUT)
|
print("[Sat] Output: %s" % OUTPUT)
|
||||||
log("[Sat] Zoom: 0-%d | Threads: %d | Tiles: %d" % (MAX_ZOOM, THREADS, total))
|
print("[Sat] Zoom: 0-%d | Threads: %d | Tiles: %d" % (MAX_ZOOM, THREADS, total))
|
||||||
log("[Sat] Quelle: Sentinel-2 cloudless 2021 (EOX, CC BY 4.0)")
|
print("[Sat] Quelle: Sentinel-2 cloudless 2021 (EOX, CC BY 4.0)")
|
||||||
log("[Sat] Resume: bereits heruntergeladene Tiles werden übersprungen")
|
|
||||||
conn = init_db(OUTPUT)
|
conn = init_db(OUTPUT)
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
n = 0
|
futs = [
|
||||||
# Bounded queue: max THREADS*4 Futures gleichzeitig im Speicher
|
do_tile
|
||||||
# verhindert OOM bei 5.5 Mio Tasks
|
for z in range(MAX_ZOOM + 1)
|
||||||
sem = threading.Semaphore(THREADS * 4)
|
for x in range(1 << z)
|
||||||
|
for y in range(1 << z)
|
||||||
def submit_tile(ex, z, x, y):
|
]
|
||||||
sem.acquire()
|
|
||||||
fut = ex.submit(do_tile, conn, z, x, y)
|
|
||||||
fut.add_done_callback(lambda _: sem.release())
|
|
||||||
return fut
|
|
||||||
|
|
||||||
with ThreadPoolExecutor(max_workers=THREADS) as ex:
|
with ThreadPoolExecutor(max_workers=THREADS) as ex:
|
||||||
futs = []
|
submitted = [ex.submit(do_tile, conn, z, x, y)
|
||||||
for z in range(MAX_ZOOM + 1):
|
for z in range(MAX_ZOOM + 1)
|
||||||
for x in range(1 << z):
|
for x in range(1 << z)
|
||||||
for y in range(1 << z):
|
for y in range(1 << z)]
|
||||||
futs.append(submit_tile(ex, z, x, y))
|
for n, f in enumerate(as_completed(submitted), 1):
|
||||||
for n, f in enumerate(as_completed(futs), 1):
|
|
||||||
f.result()
|
f.result()
|
||||||
if n % 1000 == 0 or n == total:
|
if n % 1000 == 0 or n == total:
|
||||||
dt = time.time() - t0 or 0.001
|
dt = time.time() - t0 or 0.001
|
||||||
eta = (total - n) / n * dt / 3600
|
eta = (total - n) / n * dt / 3600
|
||||||
log("[Sat] %5.1f%% %d/%d ok=%d skip=%d err=%d %.0ft/s ETA=%.1fh" % (
|
print("[Sat] %5.1f%% %d/%d ok=%d skip=%d err=%d %.0ft/s ETA=%.1fh" % (
|
||||||
n / total * 100, n, total,
|
n / total * 100, n, total,
|
||||||
stats["ok"], stats["skip"], stats["err"],
|
stats["ok"], stats["skip"], stats["err"],
|
||||||
n / dt, eta))
|
n / dt, eta))
|
||||||
|
|
@ -116,11 +105,11 @@ def main():
|
||||||
if pending:
|
if pending:
|
||||||
conn.executemany("INSERT OR REPLACE INTO tiles VALUES(?,?,?,?)", pending)
|
conn.executemany("INSERT OR REPLACE INTO tiles VALUES(?,?,?,?)", pending)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
log("[Sat] Erstelle Index...")
|
print("[Sat] Erstelle Index...")
|
||||||
conn.execute("CREATE UNIQUE INDEX IF NOT EXISTS idx ON tiles(zoom_level, tile_column, tile_row)")
|
conn.execute("CREATE UNIQUE INDEX IF NOT EXISTS idx ON tiles(zoom_level, tile_column, tile_row)")
|
||||||
conn.execute("ANALYZE")
|
conn.execute("ANALYZE")
|
||||||
conn.close()
|
conn.close()
|
||||||
log("[Sat] Fertig %.1fh -- %s" % ((time.time() - t0) / 3600, OUTPUT))
|
print("[Sat] Fertig %.1fh -- %s" % ((time.time() - t0) / 3600, OUTPUT))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue