2026-09-21 06:29:08 +03:00
2026-09-21 03:53:15 +03:00
2026-09-21 06:29:08 +03:00
2026-09-21 03:53:15 +03:00
2026-09-21 06:29:08 +03:00
2026-09-21 04:51:23 +03:00
2026-09-21 06:29:08 +03:00
2026-09-21 03:53:15 +03:00
2026-09-21 03:53:15 +03:00
2026-09-21 03:53:15 +03:00
2026-09-21 03:53:15 +03:00
2026-09-21 06:29:08 +03:00
2026-09-21 03:53:15 +03:00
2026-09-21 06:29:08 +03:00
2026-09-21 03:53:15 +03:00

Tile Server

ASP.NET Core сервер векторных тайлов для клиентов MapLibre GL.

Ежедневно (и при старте) воркер:

  1. Скачивает все настроенные OSM-extract’ы с Geofabrik (и любых других HTTP-ссылок на .osm.pbf).
  2. Собирает из них OpenMapTiles MBTiles через planetiler-openmaptiles.
  3. Отдаёт тайлы, 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.jsonTileServer: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.

S
Description
No description provided
Readme
1.2 MiB
Languages
C# 49.5%
TypeScript 27.9%
CSS 15.1%
JavaScript 3.6%
HTML 3.3%
Other 0.6%