feat: initial tile server setup
- TileServer-GL + nginx reverse proxy (docker-compose) - CORS-Konfiguration für MediaWiki, Nextcloud & weitere Dienste - Rate-Limiting & Tile-Caching-Header via nginx - config/config.json: OSM + Satellitenkacheln - scripts/download-data.sh: Planetiler (OSM), Sentinel-2 Hinweise - docs: API-Endpoints, MediaWiki Kartographer, Nextcloud Maps - .gitignore: MBTiles/PMTiles und .env ausgeschlossen
This commit is contained in:
commit
bfd8dfdf96
11 changed files with 383 additions and 0 deletions
2
.env.example
Normal file
2
.env.example
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Beispiel – in .env kopieren und anpassen
|
||||||
|
TILE_PORT=8080
|
||||||
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Datendateien – nicht im Repo (können mehrere GB groß sein)
|
||||||
|
data/*.mbtiles
|
||||||
|
data/*.pmtiles
|
||||||
|
data/fonts/
|
||||||
|
data/sprites/
|
||||||
|
data/styles/
|
||||||
|
|
||||||
|
# Laufzeit
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
*.log
|
||||||
29
config/config.json
Normal file
29
config/config.json
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"paths": {
|
||||||
|
"root": "",
|
||||||
|
"fonts": "fonts",
|
||||||
|
"sprites": "sprites",
|
||||||
|
"styles": "styles",
|
||||||
|
"mbtiles": ""
|
||||||
|
},
|
||||||
|
"serveAllFonts": true,
|
||||||
|
"serveAllStyles": true
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"osm-openmaptiles": {
|
||||||
|
"mbtiles": "osm.mbtiles"
|
||||||
|
},
|
||||||
|
"satellite": {
|
||||||
|
"mbtiles": "satellite.mbtiles"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"styles": {
|
||||||
|
"osm-bright": {
|
||||||
|
"style": "styles/osm-bright/style.json"
|
||||||
|
},
|
||||||
|
"satellite-hybrid": {
|
||||||
|
"style": "styles/satellite-hybrid/style.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
data/.gitkeep
Normal file
7
data/.gitkeep
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# MBTiles-Dateien hier ablegen
|
||||||
|
#
|
||||||
|
# Benötigte Dateien (nicht im Git, da zu groß):
|
||||||
|
# osm.mbtiles – OpenStreetMap Vektorkacheln (via Planetiler)
|
||||||
|
# satellite.mbtiles – Satellitenkacheln
|
||||||
|
#
|
||||||
|
# Download-Skript: ../scripts/download-data.sh
|
||||||
30
docker-compose.yml
Normal file
30
docker-compose.yml
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
services:
|
||||||
|
tileserver:
|
||||||
|
image: maptiler/tileserver-gl:latest
|
||||||
|
container_name: rd13_tileserver
|
||||||
|
expose:
|
||||||
|
- "8080"
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./config/config.json:/data/config.json:ro
|
||||||
|
command: ["--config", "/data/config.json", "--port", "8080", "--verbose"]
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 20s
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: rd13_tileserver_proxy
|
||||||
|
ports:
|
||||||
|
- "${TILE_PORT:-8080}:80"
|
||||||
|
volumes:
|
||||||
|
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./nginx/cors.conf:/etc/nginx/cors.conf:ro
|
||||||
|
depends_on:
|
||||||
|
tileserver:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
34
docs/api-endpoints.md
Normal file
34
docs/api-endpoints.md
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Allgemeine Tile-Server Endpunkte
|
||||||
|
#
|
||||||
|
# Sobald der Server läuft, sind folgende Endpoints verfügbar:
|
||||||
|
#
|
||||||
|
# Web-Interface:
|
||||||
|
# http://SERVER:PORT/
|
||||||
|
#
|
||||||
|
# Styles (Raster-Tiles, PNG):
|
||||||
|
# http://SERVER:PORT/styles/osm-bright/{z}/{x}/{y}.png ← OSM
|
||||||
|
# http://SERVER:PORT/styles/satellite-hybrid/{z}/{x}/{y}.png ← Satellit
|
||||||
|
# http://SERVER:PORT/styles/osm-bright/{z}/{x}/{y}@2x.png ← Retina
|
||||||
|
#
|
||||||
|
# Daten (Vektor-Tiles, PBF):
|
||||||
|
# http://SERVER:PORT/data/osm-openmaptiles/{z}/{x}/{y}.pbf
|
||||||
|
# http://SERVER:PORT/data/satellite/{z}/{x}/{y}.png
|
||||||
|
#
|
||||||
|
# TileJSON (Metadaten für Leaflet, MapLibre, etc.):
|
||||||
|
# http://SERVER:PORT/styles/osm-bright.json
|
||||||
|
# http://SERVER:PORT/data/osm-openmaptiles.json
|
||||||
|
#
|
||||||
|
# WMTS (für QGIS, ArcGIS, etc.):
|
||||||
|
# http://SERVER:PORT/styles/osm-bright/wmts
|
||||||
|
#
|
||||||
|
# Leaflet.js Beispiel:
|
||||||
|
# L.tileLayer('http://SERVER:PORT/styles/osm-bright/{z}/{x}/{y}.png', {
|
||||||
|
# attribution: '© OpenMapTiles © OpenStreetMap contributors',
|
||||||
|
# maxZoom: 20
|
||||||
|
# }).addTo(map);
|
||||||
|
#
|
||||||
|
# MapLibre GL Beispiel:
|
||||||
|
# new maplibregl.Map({
|
||||||
|
# style: 'http://SERVER:PORT/styles/osm-bright.json',
|
||||||
|
# container: 'map'
|
||||||
|
# });
|
||||||
35
docs/mediawiki-config.php
Normal file
35
docs/mediawiki-config.php
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# MediaWiki Kartographer – Konfiguration für LocalSettings.php
|
||||||
|
#
|
||||||
|
# Füge diese Zeilen in deine LocalSettings.php ein.
|
||||||
|
# Ersetze TILE_SERVER_URL mit der tatsächlichen URL deines Servers.
|
||||||
|
#
|
||||||
|
# Dokumentation: https://www.mediawiki.org/wiki/Extension:Kartographer
|
||||||
|
|
||||||
|
# Kartographer aktivieren
|
||||||
|
wfLoadExtension( 'Kartographer' );
|
||||||
|
|
||||||
|
# Tile-Server URL (dein selbst gehosteter Server)
|
||||||
|
$wgKartographerMapServer = 'http://TILE_SERVER_URL:8080';
|
||||||
|
|
||||||
|
# Welche Kartenstile stehen zur Verfügung?
|
||||||
|
# Die Namen entsprechen den Keys in config/config.json → "styles"
|
||||||
|
$wgKartographerStyles = [
|
||||||
|
'osm-bright', # OpenStreetMap Vektorkarte
|
||||||
|
'satellite-hybrid', # Satellitenkarte
|
||||||
|
];
|
||||||
|
|
||||||
|
# Standard-Stil
|
||||||
|
$wgKartographerDfltStyle = 'osm-bright';
|
||||||
|
|
||||||
|
# Tile-URL-Muster für Raster-Tiles (XYZ)
|
||||||
|
# TileServer-GL stellt Tiles unter /styles/{style}/{z}/{x}/{y}.png bereit
|
||||||
|
$wgKartographerSrcsetScales = [ 1, 1.5, 2 ];
|
||||||
|
|
||||||
|
# Optional: statische Kartenbilder für Vorschau (Mapshot)
|
||||||
|
# $wgKartographerStaticFullWidth = true;
|
||||||
|
|
||||||
|
# Beispiel-Verwendung in einem Wiki-Artikel:
|
||||||
|
# <maplink zoom="12" latitude="48.137" longitude="11.576">
|
||||||
|
# {"type":"Feature","geometry":{"type":"Point","coordinates":[11.576,48.137]},
|
||||||
|
# "properties":{"title":"München","description":"Landeshauptstadt"}}
|
||||||
|
# </maplink>
|
||||||
27
docs/nextcloud-config.md
Normal file
27
docs/nextcloud-config.md
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Nextcloud Maps – eigenen Tile-Server verwenden
|
||||||
|
#
|
||||||
|
# Nextcloud Maps App: https://apps.nextcloud.com/apps/maps
|
||||||
|
#
|
||||||
|
# Konfiguration in Nextcloud Admin-Panel:
|
||||||
|
# Einstellungen → Verwaltung → Maps → Tile server URL
|
||||||
|
#
|
||||||
|
# Tile-Server-URLs (TileServer-GL XYZ-Format):
|
||||||
|
#
|
||||||
|
# OSM Vektorkarte (als Rasterbild gerendert):
|
||||||
|
# http://TILE_SERVER_URL:8080/styles/osm-bright/{z}/{x}/{y}.png
|
||||||
|
#
|
||||||
|
# Satellitenkarte:
|
||||||
|
# http://TILE_SERVER_URL:8080/styles/satellite-hybrid/{z}/{x}/{y}.png
|
||||||
|
#
|
||||||
|
# Rohe Vektorkacheln (OpenMapTiles Schema):
|
||||||
|
# http://TILE_SERVER_URL:8080/data/osm-openmaptiles/{z}/{x}/{y}.pbf
|
||||||
|
#
|
||||||
|
# Über occ (Kommandozeile) setzen:
|
||||||
|
# php occ config:app:set maps tileserverUrl \
|
||||||
|
# --value="http://TILE_SERVER_URL:8080/styles/osm-bright/{z}/{x}/{y}.png"
|
||||||
|
|
||||||
|
# Beispiel für docker-compose override wenn Nextcloud im selben Stack läuft:
|
||||||
|
#
|
||||||
|
# nextcloud:
|
||||||
|
# environment:
|
||||||
|
# MAPS_TILE_SERVER: "http://rd13_tileserver_proxy/styles/osm-bright/{z}/{x}/{y}.png"
|
||||||
4
nginx/cors.conf
Normal file
4
nginx/cors.conf
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Shared CORS headers – included by nginx.conf
|
||||||
|
# Wird automatisch auf alle Responses angewendet.
|
||||||
|
# Für produktiven Betrieb kann Origin auf deine Domains eingeschränkt werden:
|
||||||
|
# add_header Access-Control-Allow-Origin "https://wiki.example.com" always;
|
||||||
53
nginx/nginx.conf
Normal file
53
nginx/nginx.conf
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
worker_processes auto;
|
||||||
|
events { worker_connections 1024; }
|
||||||
|
|
||||||
|
http {
|
||||||
|
include mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
sendfile on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
# Rate limiting – schützt vor Missbrauch durch externe Dienste
|
||||||
|
limit_req_zone $binary_remote_addr zone=tiles:10m rate=100r/s;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
# CORS für alle Clients (MediaWiki, Nextcloud, etc.)
|
||||||
|
include /etc/nginx/cors.conf;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
limit_req zone=tiles burst=200 nodelay;
|
||||||
|
|
||||||
|
proxy_pass http://tileserver:8080;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Tile-Caching-Header
|
||||||
|
proxy_hide_header Cache-Control;
|
||||||
|
add_header Cache-Control "public, max-age=86400, stale-while-revalidate=3600";
|
||||||
|
|
||||||
|
# CORS-Header (aus cors.conf)
|
||||||
|
add_header Access-Control-Allow-Origin "*" always;
|
||||||
|
add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
|
||||||
|
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept" always;
|
||||||
|
}
|
||||||
|
|
||||||
|
# CORS Preflight
|
||||||
|
location ~* \.(pbf|png|jpg|json)$ {
|
||||||
|
if ($request_method = OPTIONS) {
|
||||||
|
add_header Access-Control-Allow-Origin "*";
|
||||||
|
add_header Access-Control-Allow-Methods "GET, OPTIONS";
|
||||||
|
add_header Access-Control-Max-Age 86400;
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy_pass http://tileserver:8080;
|
||||||
|
add_header Access-Control-Allow-Origin "*" always;
|
||||||
|
add_header Cache-Control "public, max-age=86400";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
150
scripts/download-data.sh
Normal file
150
scripts/download-data.sh
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# download-data.sh – Kartendaten für den rd13 Tile Server herunterladen
|
||||||
|
#
|
||||||
|
# Verwendung:
|
||||||
|
# ./scripts/download-data.sh [region]
|
||||||
|
#
|
||||||
|
# Regionen:
|
||||||
|
# europe-dach – Deutschland, Österreich, Schweiz (Standard)
|
||||||
|
# germany – nur Deutschland
|
||||||
|
# planet – gesamter Planet (groß!)
|
||||||
|
# satellite – Sentinel-2 cloudless Satellitenkacheln (niedrig/mittel Zoom)
|
||||||
|
# =============================================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
DATA_DIR="$SCRIPT_DIR/../data"
|
||||||
|
mkdir -p "$DATA_DIR"
|
||||||
|
|
||||||
|
REGION="${1:-europe-dach}"
|
||||||
|
|
||||||
|
# ---- OSM-Vektorkacheln via Planetiler ------------------------------------
|
||||||
|
download_osm() {
|
||||||
|
local region="$1"
|
||||||
|
local jar="$DATA_DIR/planetiler.jar"
|
||||||
|
|
||||||
|
# Planetiler herunterladen falls nicht vorhanden
|
||||||
|
if [[ ! -f "$jar" ]]; then
|
||||||
|
echo "[OSM] Lade Planetiler herunter..."
|
||||||
|
curl -L -o "$jar" \
|
||||||
|
"https://github.com/onthegomap/planetiler/releases/latest/download/planetiler.jar"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$region" in
|
||||||
|
germany)
|
||||||
|
AREA="germany"
|
||||||
|
DOWNLOAD="https://download.geofabrik.de/europe/germany-latest.osm.pbf"
|
||||||
|
;;
|
||||||
|
europe-dach)
|
||||||
|
# DACH als Extrakt
|
||||||
|
AREA="dach"
|
||||||
|
DOWNLOAD="https://download.geofabrik.de/europe/dach-latest.osm.pbf"
|
||||||
|
;;
|
||||||
|
planet)
|
||||||
|
AREA="planet"
|
||||||
|
DOWNLOAD="" # Planetiler lädt selbst herunter
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unbekannte Region: $region"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "[OSM] Erzeuge osm.mbtiles für Region: $region"
|
||||||
|
if [[ "$region" == "planet" ]]; then
|
||||||
|
java -Xmx8g -jar "$jar" \
|
||||||
|
--download \
|
||||||
|
--output="$DATA_DIR/osm.mbtiles"
|
||||||
|
else
|
||||||
|
# OSM-PBF herunterladen
|
||||||
|
local pbf="$DATA_DIR/${AREA}.osm.pbf"
|
||||||
|
if [[ ! -f "$pbf" ]]; then
|
||||||
|
echo "[OSM] Lade PBF-Datei: $DOWNLOAD"
|
||||||
|
curl -L -o "$pbf" "$DOWNLOAD"
|
||||||
|
fi
|
||||||
|
java -Xmx4g -jar "$jar" \
|
||||||
|
--area="$AREA" \
|
||||||
|
--osm-path="$pbf" \
|
||||||
|
--output="$DATA_DIR/osm.mbtiles"
|
||||||
|
fi
|
||||||
|
echo "[OSM] Fertig: $DATA_DIR/osm.mbtiles"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- Satellit: Sentinel-2 cloudless (OpenMapTiles / maptiler) ------------
|
||||||
|
download_satellite() {
|
||||||
|
echo ""
|
||||||
|
echo "[Satellit] Hinweis:"
|
||||||
|
echo " Kostenlose Satelliten-MBTiles sind nur für niedrige Zoomstufen (0-10)"
|
||||||
|
echo " verfügbar. Für höhere Auflösung gibt es zwei Optionen:"
|
||||||
|
echo ""
|
||||||
|
echo " 1) NASA GIBS (kostenlos, TMS/WMTS, kein Download nötig):"
|
||||||
|
echo " https://gibs.earthdata.nasa.gov/wmts/"
|
||||||
|
echo " → Einfach in config.json als 'tilejson'-Source eintragen."
|
||||||
|
echo ""
|
||||||
|
echo " 2) Sentinel-2 cloudless (maptiler.com, kostenloser Account für self-hosted):"
|
||||||
|
echo " https://www.maptiler.com/data/satellite-mediumres/"
|
||||||
|
echo " → MBTiles manuell herunterladen und als data/satellite.mbtiles ablegen."
|
||||||
|
echo ""
|
||||||
|
echo " 3) Eigene GeoTIFFs → MBTiles mit gdal2tiles:"
|
||||||
|
echo " gdal2tiles.py --zoom=0-14 input.tif data/satellite/"
|
||||||
|
echo " mb-util data/satellite/ data/satellite.mbtiles"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- Fonts & Sprites für OSM Bright Style --------------------------------
|
||||||
|
download_assets() {
|
||||||
|
local fonts_dir="$DATA_DIR/fonts"
|
||||||
|
local sprites_dir="$DATA_DIR/sprites"
|
||||||
|
local styles_dir="$DATA_DIR/styles"
|
||||||
|
|
||||||
|
mkdir -p "$fonts_dir" "$sprites_dir" "$styles_dir"
|
||||||
|
|
||||||
|
if [[ ! -d "$fonts_dir/Open Sans Regular" ]]; then
|
||||||
|
echo "[Assets] Lade OpenMapTiles Fonts herunter..."
|
||||||
|
TMP=$(mktemp -d)
|
||||||
|
curl -L -o "$TMP/fonts.zip" \
|
||||||
|
"https://github.com/openmaptiles/fonts/releases/latest/download/v3.0.zip" \
|
||||||
|
|| { echo "[Assets] Font-Download fehlgeschlagen – bitte manuell von"; \
|
||||||
|
echo " https://github.com/openmaptiles/fonts/releases herunterladen"; \
|
||||||
|
rm -rf "$TMP"; }
|
||||||
|
if [[ -f "$TMP/fonts.zip" ]]; then
|
||||||
|
unzip -q "$TMP/fonts.zip" -d "$fonts_dir"
|
||||||
|
rm -rf "$TMP"
|
||||||
|
echo "[Assets] Fonts installiert."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "[Assets] Fonts bereits vorhanden."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -d "$styles_dir/osm-bright" ]]; then
|
||||||
|
echo "[Assets] Lade OSM Bright GL Style herunter..."
|
||||||
|
TMP=$(mktemp -d)
|
||||||
|
curl -L -o "$TMP/style.zip" \
|
||||||
|
"https://github.com/openmaptiles/osm-bright-gl-style/releases/latest/download/v1.9.zip" \
|
||||||
|
|| { echo "[Assets] Style-Download fehlgeschlagen."; rm -rf "$TMP"; }
|
||||||
|
if [[ -f "$TMP/style.zip" ]]; then
|
||||||
|
unzip -q "$TMP/style.zip" -d "$TMP/extracted"
|
||||||
|
mv "$TMP/extracted/"*/ "$styles_dir/osm-bright"
|
||||||
|
rm -rf "$TMP"
|
||||||
|
echo "[Assets] OSM Bright Style installiert."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "[Assets] OSM Bright Style bereits vorhanden."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- Hauptlogik ----------------------------------------------------------
|
||||||
|
echo "=== rd13 Tile Server – Daten-Download ==="
|
||||||
|
echo "Region: $REGION"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [[ "$REGION" == "satellite" ]]; then
|
||||||
|
download_satellite
|
||||||
|
else
|
||||||
|
download_osm "$REGION"
|
||||||
|
download_assets
|
||||||
|
download_satellite
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Abgeschlossen ==="
|
||||||
|
echo "Starte den Server mit: docker compose up -d"
|
||||||
Loading…
Add table
Reference in a new issue