# Anforderungen – rd13_tile_server Letzte Aktualisierung: 2026-06-22 --- ## 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) --- ## REQ-001 – Tile Server öffentlich erreichbar **Status:** ✅ umgesetzt Der Tile Server muss über HTTPS unter einer öffentlichen Domain erreichbar sein, damit externe Dienste (MediaWiki, Home Assistant, Nextcloud) Karten laden können. **Akzeptanzkriterien:** - Erreichbar unter `https://tiles.rd13server.de` - SSL-Terminierung via NPM - Health-Endpunkt antwortet mit HTTP 200 --- ## REQ-002 – Rate Limiting für den öffentlichen Tile-Endpunkt **Status:** 🔴 offen – Implementierung erforderlich vor Live-Gang Da der Server unter `https://tiles.rd13server.de` öffentlich erreichbar ist, muss er gegen unautorisierten Massenkonsum und DoS-Angriffe geschützt werden. ### Anforderungen | ID | Anforderung | Priorität | |---|---|---| | REQ-002.1 | Rate Limiting: max. 10 Tile-Requests/Sekunde pro IP, Burst 60 | hoch | | REQ-002.2 | Verbindungslimit: max. 20 gleichzeitige Verbindungen pro IP | hoch | | REQ-002.3 | WebUI (`/`) nur aus LAN (192.168.178.0/24) erreichbar | mittel | | REQ-002.4 | `/health` und `/catalog` nur aus LAN erreichbar | mittel | | REQ-002.5 | HTTP-Antwort 429 bei Überschreitung mit Retry-After-Header | mittel | | REQ-002.6 | Caching-Header für Tiles (max-age 24h) zur Lastreduzierung | mittel | ### Implementierungsplan **Schicht 1 – NPM Advanced Config (primärer Schutz)** Rate Limiting passiert im Nginx Proxy Manager auf Proxy-Host-Ebene. NPM erlaubt freie nginx-Direktiven im Feld „Advanced". ```nginx # -- Rate Limiting -- # Speicher: 10 MB reicht fuer ~160.000 IP-Adressen limit_req_zone $binary_remote_addr zone=tiles:10m rate=10r/s; limit_conn_zone $binary_remote_addr zone=tile_conn:10m; # Burst von 60 erlaubt schnellen Kartenaufbau beim ersten Laden limit_req zone=tiles burst=60 nodelay; limit_conn tile_conn 20; # 429 statt 503 zurueckgeben limit_req_status 429; limit_conn_status 429; # -- Caching-Header fuer Tile-Endpunkte -- add_header Cache-Control "public, max-age=86400, stale-while-revalidate=3600" always; add_header Vary "Accept-Encoding" always; # -- Sicherheits-Header -- add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; ``` **Schicht 2 – Interne Endpunkte abschirmen (im selben NPM Advanced Block)** WebUI, Health und Catalog sollen von außen nicht erreichbar sein. Da NPM keinen bedingten Block pro Location direkt unterstuetzt, wird ein zweiter Proxy-Host fuer interne Endpunkte empfohlen: ``` Oeffentlicher Proxy-Host: tiles.rd13server.de -> http://HOST:9982 → nur Tile-Pfade freigeben, alle anderen 403 → Rate Limiting aktiv Interner Proxy-Host (kein SSL nötig): tiles-internal.lan -> http://192.168.178.5:9982 → kein Rate Limiting → nur aus LAN erreichbar (Firewall / Access List im NPM) ``` Alternativ: Einzelner Proxy-Host mit NPM Access List „LAN only" fuer `/` und `/catalog`. **Schicht 3 – fail2ban (optionaler zweiter Layer)** ```ini # /etc/fail2ban/filter.d/nginx-tile-ratelimit.conf [Definition] failregex = limiting requests, excess.* by zone "tiles".* client: ignoreregex = # /etc/fail2ban/jail.local [nginx-tile-ratelimit] enabled = true port = http,https filter = nginx-tile-ratelimit logpath = /var/log/nginx/access.log maxretry = 10 findtime = 60 bantime = 3600 ``` ### Reihenfolge der Umsetzung 1. NPM Proxy-Host fuer `tiles.rd13server.de` anlegen (falls noch nicht vorhanden) 2. Rate-Limiting-Block in NPM Advanced Config eintragen 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 5. fail2ban optional installieren und konfigurieren --- ## REQ-003 – Caching (nicht-funktional) **Status:** 🔴 offen Tiles sollen gecacht werden, um wiederholte Requests zu vermeiden und die Last auf den Server zu reduzieren. **Akzeptanzkriterien:** - Cache-Control-Header auf allen Tile-Responses: `public, max-age=86400` - NPM leitet Header durch (keine Überschreibung) --- ## REQ-004 – MediaWiki Integration **Status:** ✅ umgesetzt (LocalSettings konfiguriert) Kartographer nutzt `https://tiles.rd13server.de` als Tile-Server. --- ## REQ-005 – Home Assistant Integration **Status:** 📋 dokumentiert, nicht getestet Satellit-Tiles als Raster-Layer in HA-Map-Card einbindbar. **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 ``` --- ## REQ-006 – Satellit-Hybrid und Luftbild-Detailtiefe **Status:** 🧊 **AUF EIS** – Entscheidung getroffen, Implementierung folgt bei Bedarf **Dezision:** 2026-06-22 umfangreiche Provider-Analyse durchgeführt. Feststellung: Mit freien Datenquellen ist Vollabdeckung z13/z14+ nicht praktikabel; empfohlen wird MapTiler On-Prem für Private Nutzung. ### Aktuelle Situation (z11 Sentinel-2) Der aktuelle Satelliten-Datensatz (`data/satellite.mbtiles`) basiert auf Sentinel-2 cloudless 2021 und endet real bei `maxzoom=11` (20 GB, 5.6 Mio Tiles). Bei `z=14` oder `z=16` wird das Raster nur hochskaliert. Häuser, kleine Straßen und Luftbilddetails sind nicht vorhanden. ```text satellite.mbtiles format: jpg minzoom: 0 maxzoom: 11 size: ~20 GB (JPEG) quality: 10–60m Pixel (Sentinel-2) description: Sentinel-2 cloudless 2021 (EOX CC BY 4.0) ``` ### Provider-Matrix (Private Offline-Nutzung) | **Quelle** | **Qualität** | **Lizenz** | **Kosten** | **Self-Hosting** | **Speicher z16** | |---|---|---|---|---|---| | **MapTiler On-Prem** | ⭐⭐⭐⭐⭐ (z16–17) | ✅ Explizit erlaubt | €1.500 (One-Time) | ✅ JA | 200–500 GB | | **Sentinel-2 (EOX)** | ⭐⭐⭐ (z0–11) | ✅ CC BY 4.0 | Kostenlos | ✅ JA | N/A | | **Google Maps API** | ⭐⭐⭐⭐⭐ | ❌ Offline verboten | €600–1.200/Mo | ❌ NEIN | N/A | | **Mapbox** | ⭐⭐⭐⭐ | ❌ Bulk-DL verboten | $600–800/Mo | ❌ NEIN | N/A | | **Sentinel Hub Free** | ⭐⭐⭐ | ✅ Kostenlos | Kostenlos | ⚠️ Script | 1.333+ Jahre¹ | ¹ Kostenlos: 100 PU/Mo = 100 z14-Tiles/Mo. Deutschland z14 = 1,6 Mio Tiles = 16.000 Monate = **1.333 Jahre Betrieb**. ### Kostenvergleich (3 Jahre, Private Nutzung) | Szenario | **Jahr 1** | **Jahr 2+** | **Speicher** | **Gesamt** | |---|---|---|---|---| | Status Quo (z11) | €0 | €0 | 20 GB | ✅ **€0** | | **MapTiler z14** | €500–800 | €0 | 30–50 GB | ✅ **€500–800** | | **MapTiler z16** | €1.200–1.500 | €0 | 200–300 GB | ✅ **€1.200–1.500** | | Sentinel Hub Free | €0 | €0 | 20 GB | ❌ **1.333 Jahre Betrieb** | ### Technische Integration (Option: MapTiler On-Prem) Falls Upgrade beschlossen: | Datei | Änderung | Impact | |---|---|---| | `docker-compose.yml` | Volume `/data/satellite-hq.mbtiles` | 1 Zeile | | `config/tileserver.json` | Source `satellite-hq` eintragen | 3 Zeilen | | `config/styles/satelite-world.json` | Layer hinzufügen | 5 Zeilen | **Aufwand:** Niedrig (~2 Std Setup + Testing). ### Next Steps 1. **Phase 1 (Jetzt):** z11 Sentinel-2 in Produktion testen (2–4 Wochen) - Frage: Reicht z11 für MediaWiki/HA/Nextcloud aus? 2. **Phase 2 (Falls nötig):** MapTiler On-Prem kaufen - Kontakt: sales@maptiler.com - Budget: €500–1.500 (One-Time) - Lieferzeit: 1–5 Tage 3. **Phase 3 (Integration):** 4 Dateien anpassen, `docker compose up -d` 4. **Phase 4 (Doku):** ADR-003 erstellen (Satellite-Entscheidungslog)