Tile Server
ASP.NET Core сервер векторных тайлов для клиентов MapLibre GL.
Ежедневно (и при старте) воркер:
- Скачивает все настроенные OSM-extract’ы с Geofabrik (и любых других HTTP-ссылок на
.osm.pbf). - Собирает из них OpenMapTiles MBTiles через planetiler-openmaptiles.
- Отдаёт тайлы, TileJSON и стили карты.
Что нужно
- .NET 8 SDK
- Java 21+ в
PATH(или путь вTileServer:JavaPath) — без Java тайлы не соберутся, уже готовые MBTiles сервер всё равно отдаст - Диск: 5–10× размер PBF. ЦФО до z15 — ориентир несколько ГБ готового MBTiles плюс столько же на staging во время сборки
- RAM: контейнер ~12g.
TileServer:JvmMaxHeap— только Java heap, держите ~⅓ лимита (по умолчанию4g). Остальное — mmap/файлы Planetiler и Kestrel. Код 137 = OOM killer, не переполнение-Xmx.
Тайлы собираются через OpenMapTiles. Схема рассчитана на z0–z14 (дефолт MapTiler/Planetiler). Жёсткий потолок planetiler-openmaptiles 3.16 — z15; z16+ этот JAR не умеет. Ближе z15 MapLibre overzoom’ит те же тайлы до z18.
Первая сборка ЦФО занимает часы. Для быстрой проверки временно поставьте Monaco:
"Url": "https://download.geofabrik.de/europe/monaco-latest.osm.pbf"
Запуск
dotnet run --project src/TileServer.Api
Откройте http://localhost:5088 — тестовая карта, выбор источника и стиля.
docker compose up -d --build
Сервис слушает 51300 (внутри контейнера 8080). Данные (PBF, MBTiles, стили, ключи) — Docker volume tile-server-data, деплой кода его не затирает. Не вызывайте docker compose down -v.
Если на сервере уже есть ./data, один раз перенесите:
docker run --rm -v "$(pwd)/data:/from:ro" -v tile-server-data:/to alpine sh -c "cp -a /from/. /to/"
docker compose up -d --build
API
| Метод | URL | Назначение |
|---|---|---|
GET |
/api/v1/tiles/{source}/{z}/{x}/{y}.pbf |
векторный тайл (MapLibre XYZ) |
GET |
/api/v1/tiles/{source}.json |
TileJSON |
GET |
/api/v1/styles |
список стилей |
GET |
/api/v1/styles/{name}?source={source} |
MapLibre style JSON |
PUT |
/api/v1/styles/{name} |
добавить/обновить стиль |
GET |
/api/v1/sources |
extract’ы и статус воркера |
PUT |
/api/v1/sources/{id} |
добавить регион (ещё одна ссылка на PBF) |
POST |
/api/v1/sync |
прогнать все extract’ы сейчас |
POST |
/api/v1/sync/{id} |
прогнать один extract |
GET |
/ |
демо MapLibre |
Алиасы без /api/v1: /tiles/{source}/{z}/{x}/{y}.pbf.
Несколько регионов
В appsettings.json → TileServer:Extracts можно перечислить сколько угодно выгрузок. Воркер проходит все Enabled: true по очереди (чтобы не упереться в RAM).
"Extracts": [
{
"Id": "central-fed-district",
"Name": "Центральный федеральный округ",
"Url": "https://download.geofabrik.de/russia/central-fed-district-latest.osm.pbf",
"Center": [37.6173, 55.7558]
},
{
"Id": "northwestern-fed-district",
"Name": "Северо-Западный федеральный округ",
"Url": "https://download.geofabrik.de/russia/northwestern-fed-district-latest.osm.pbf",
"Center": [30.3141, 59.9386]
}
]
То же самое в runtime: PUT /api/v1/sources/{id} (пишет data/extracts.json, переживает рестарт).
Расписание: cron TileServer:Sync:Cron, по умолчанию 0 3 * * * UTC. Если PBF не изменился (HTTP 304) и MBTiles уже есть — пересборка пропускается, кроме случая когда в конфиге MaxZoom больше, чем в текущем тайсете (после поднятия z14→z15 сборка пойдёт сама).
Клиенты в TileJSON/стиле видят maxzoom собранной пирамиды (14/15): MapLibre сам растягивает эти тайлы ближе. Если кто-то всё же запросит z16–18, сервер нарежет их из родителя. Вне ЦФО отдаётся 204, не 404.
Стили
Кладёте data/styles/{name}.json (MapLibre Style Spec v8, схема слоёв OpenMapTiles) или делаете PUT /api/v1/styles/{name}.
Клиент запрашивает стиль по имени:
GET /api/v1/styles/osm-bright?source=central-fed-district
Сервер подставляет TileJSON выбранного источника. Из коробки: osm-bright, dark, positron.
Пример источника в MapLibre:
const map = new maplibregl.Map({
container: "map",
style: "http://localhost:5088/api/v1/styles/osm-bright?source=central-fed-district",
center: [37.6173, 55.7558],
zoom: 6
});
Архитектура
Api контроллеры, демо, ProblemDetails
Application sync, tiles, styles, extracts
Domain extract, tile coordinate, ошибки
Infrastructure загрузка PBF, Planetiler, MBTiles/SQLite, файловые стили, hosted worker
Данные по умолчанию: data/ в корне репозитория (../../data относительно проекта API). В проде задайте TileServer__DataDirectory.