9bf79a15ed
PMTiles was loaded via HTTP from MinIO (10.10.10.166:9002) on an HTTPS page, causing browser mixed-content blocking — parcels invisible on geoportal. Fixes: - tile-cache nginx proxies /pmtiles/ → MinIO with Range header support - PMTILES_URL changed to relative path (resolves to HTTPS automatically) - clickableLayers includes PMTiles fill layers (click on parcels works) - Selection highlight uses PMTiles source at z13+ (was Martin z17+ only) - tippecanoe per-layer zoom ranges (terenuri z13-z18, cladiri z14-z18) skips processing millions of features at z0-z12 — faster rebuild Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
118 lines
4.1 KiB
Plaintext
118 lines
4.1 KiB
Plaintext
# nginx tile cache for Martin vector tile server
|
|
# Proxy-cache layer: 10-100x faster on repeat requests, zero PostGIS load for cached tiles
|
|
|
|
proxy_cache_path /var/cache/nginx/tiles
|
|
levels=1:2
|
|
keys_zone=tiles:64m
|
|
max_size=2g
|
|
inactive=7d
|
|
use_temp_path=off;
|
|
|
|
# Log format with cache status for monitoring (docker logs tile-cache | grep HIT/MISS)
|
|
log_format tiles '$remote_addr [$time_local] "$request" $status '
|
|
'cache=$upstream_cache_status size=$body_bytes_sent '
|
|
'time=$request_time';
|
|
|
|
server {
|
|
access_log /var/log/nginx/access.log tiles;
|
|
listen 80;
|
|
server_name _;
|
|
|
|
# Health check
|
|
location = /health {
|
|
access_log off;
|
|
return 200 "ok\n";
|
|
add_header Content-Type text/plain;
|
|
}
|
|
|
|
# nginx status (active connections, request counts) — for monitoring
|
|
location = /status {
|
|
access_log off;
|
|
stub_status on;
|
|
}
|
|
|
|
# Martin catalog endpoint (no cache)
|
|
location = /catalog {
|
|
proxy_pass http://martin:3000/catalog;
|
|
proxy_set_header Host $host;
|
|
}
|
|
|
|
# PMTiles from MinIO — HTTPS proxy for browser access (avoids mixed-content block)
|
|
# Browser fetches: /pmtiles/overview.pmtiles → MinIO http://10.10.10.166:9002/tiles/overview.pmtiles
|
|
location /pmtiles/ {
|
|
proxy_pass http://10.10.10.166:9002/tiles/;
|
|
proxy_set_header Host 10.10.10.166:9002;
|
|
proxy_http_version 1.1;
|
|
|
|
# Range requests — essential for PMTiles (byte-range tile lookups)
|
|
proxy_set_header Range $http_range;
|
|
proxy_set_header If-Range $http_if_range;
|
|
proxy_pass_request_headers on;
|
|
|
|
# Browser cache — file changes only on rebuild (~weekly)
|
|
add_header Cache-Control "public, max-age=3600, stale-while-revalidate=86400" always;
|
|
|
|
# CORS — PMTiles loaded from tools.beletage.ro page
|
|
add_header Access-Control-Allow-Origin "*" always;
|
|
add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS" always;
|
|
add_header Access-Control-Allow-Headers "Range, If-None-Match, If-Range, Accept-Encoding" always;
|
|
add_header Access-Control-Expose-Headers "Content-Range, Content-Length, ETag, Accept-Ranges" always;
|
|
|
|
# Preflight
|
|
if ($request_method = OPTIONS) {
|
|
add_header Access-Control-Allow-Origin "*";
|
|
add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS";
|
|
add_header Access-Control-Allow-Headers "Range, If-Range";
|
|
add_header Access-Control-Max-Age 86400;
|
|
add_header Content-Length 0;
|
|
return 204;
|
|
}
|
|
}
|
|
|
|
# Tile requests — cache aggressively
|
|
location / {
|
|
proxy_pass http://martin:3000;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
|
|
# Cache config — tiles change only on sync (weekly), long TTL is safe
|
|
proxy_cache tiles;
|
|
proxy_cache_key "$request_uri";
|
|
proxy_cache_valid 200 7d;
|
|
proxy_cache_valid 204 1h;
|
|
proxy_cache_valid 404 1m;
|
|
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
|
proxy_cache_lock on;
|
|
proxy_cache_lock_timeout 5s;
|
|
|
|
# Browser caching — tiles are immutable between syncs
|
|
add_header Cache-Control "public, max-age=86400, stale-while-revalidate=604800" always;
|
|
|
|
# Pass cache status header (useful for debugging)
|
|
add_header X-Cache-Status $upstream_cache_status always;
|
|
|
|
# CORS headers for tile requests
|
|
add_header Access-Control-Allow-Origin "*" always;
|
|
add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS" always;
|
|
add_header Access-Control-Allow-Headers "Range, If-None-Match, Accept-Encoding" always;
|
|
add_header Access-Control-Expose-Headers "Content-Range, Content-Length, ETag, X-Cache-Status" always;
|
|
|
|
# Handle preflight
|
|
if ($request_method = OPTIONS) {
|
|
add_header Access-Control-Allow-Origin "*";
|
|
add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS";
|
|
add_header Access-Control-Max-Age 86400;
|
|
add_header Content-Length 0;
|
|
return 204;
|
|
}
|
|
|
|
# Let Martin gzip natively — pass compressed response through to client and cache
|
|
gzip off;
|
|
|
|
# Timeouts (Martin can be slow on low-zoom tiles)
|
|
proxy_connect_timeout 10s;
|
|
proxy_read_timeout 120s;
|
|
proxy_send_timeout 30s;
|
|
}
|
|
}
|