Обновлено 12.11.2022. Добавлены пометки для Ubuntu 22. Основной упор пока на Ubuntu 20. Добавлены источники информации.
Обновлено 26.06.2024. Обновлена часть про OpenLayer
OpenStreetMap (OSM) — это создаваемая пользователями, свободно редактируемая карта мира. Можно представить это как альтернативу Google Maps с открытым исходным кодом. Эта инструкция покажет, как создать свой собственный сервер тайлов (tiles) OpenStreetMap в Ubuntu 20.04, чтобы вам не пришлось использовать чужой картографический сервис.
В этой инструкции показано, как настроить сервер растровых плиток. Если вам нужен сервер векторных плиток, вместо этого нужно перейти к инструкции по настройке векторного сервера TileServer GL/OpenMapTiles. Не знаете, какой из них лучше? Просто выберите сервер векторных плиток, который намного быстрее, чем сервер растровых плиток
Требования для развёртывания карты всей планеты довольно высоки:
Минимум 32Гб ОЗУ
1ТБ пространства на SSD
Потребуется много места на диске, если захотите ещё предварительно отрисовывать плитки, чтобы ускорить загрузку карты в браузере. Например, если вы собираетесь предварительно отобразить плитки с уровня масштабирования 0 до уровня масштабирования 15 для карты всей планеты, потребуется дополнительное место на диске объемом 460 ГБ.
Поэтому если карта всей планеты не нужна, то можно скачать карты отдельных регионов или стран.
Исходные данные:
- ОС: Ubuntu 20.04/22.04
- Пользователь с sudo правами в системе — administrator
- Подключаем как можно меньше сторонних репозиториев и пользуемся убунтовскими
Сам алгоритм работы примерно такой:
- Импортируем файлы карт в специальном формате в БД
- Ставим модули для apache2, чтобы веб-сервер мог обрабатывать запросы на генерацию карт и пересылать запросы сервисам, которые будут генерировать тайлы
- Скачиваем утилиты для вывода работы с картами через браузер
- Создаём index.html, чтобы глядеть на всё это безобразие
Для установки делаем следующие шаги, предварительно обновив систему.
Устанавливаем базу данных PostgreSQL
Для Ubuntu 20.04
sudo apt install postgresql-12 postgresql-contrib postgis postgresql-12-postgis-3 -y
Для Ubuntu 22.04
sudo apt install postgresql-14 postgresql-contrib postgis postgresql-14-postgis-3 -y
Настраиваем пользователей
Создаём пользователя для работы с базой данных карт, создаём БД с именем osm. Учтите, что некоторые утилиты типа renderd и mapnik настроены на такое имя БД. Дальше создаём расширения postgis и hstore для работы БД с картами.
sudo -u postgres createuser osm sudo -u postgres createdb -E UTF8 -O osm gis sudo -u postgres psql -c "CREATE EXTENSION postgis;" -d gis sudo -u postgres psql -c "CREATE EXTENSION hstore;" -d gis sudo -u postgres psql -c "ALTER TABLE spatial_ref_sys OWNER TO osm;" -d gis
Добавляем пользователя для работы с базой данных
sudo adduser --system --group osm
Даём необходимые права на директорию с картами текущему пользователю
sudo apt install acl sudo setfacl -R -m u:administrator:rwx /home/osm/ cd /home/osm/
Копируем репозиторий проекта карт
git clone https://github.com/gravitystorm/openstreetmap-carto.git
Скачиваем файлы карт
Есть сайт https://download.bbbike.org/osm/bbbike/ откуда можно скачать отдельные карты городов
Есть файлы областей планеты — http://download.geofabrik.de/index.html
Скачивать надо файлы с расширением .osm.pbf
Если требуется показывать карты нескольких стран, то необходимо скачивать карты каждой страны по отдельности и объединять их. Процедура объединения будет показана ниже
Скачаем карту России по примеру ниже
cd /home/osm/ wget -c http://download.geofabrik.de/russia-latest.osm.pbf
Настройка сервера PostgreSQL для лучшей производительности.
Пока скачиваются карты, настроим сервер PostgreSQL для работы с картами
Для Ubuntu 20.04
sudo nano /etc/postgresql/12/main/postgresql.conf
Для Ubuntu 22.04
sudo nano /etc/postgresql/14/main/postgresql.conf
Ищем и заменяем параметры, чтобы они были со значениями как указано ниже
shared_buffers = 15GB # (0.25*RAM) work_mem = 1GB # (1/60 RAM или около гигабайта ОЗУ) maintenance_work_mem = 8GB # (0,125*RAM) effective_cache_size = 20GB # (1/3*RAM)
Перезагружаем сервис
sudo systemctl restart postgresql
По умолчанию PostgreSQL будет пытаться использовать HugePages в оперативной памяти. Однако Linux по умолчанию не выделяет HugePages. Получим объём памяти процесса PostgreSQL.
Для Ubuntu 20.04
grep ^VmPeak /proc/$(sudo head -1 /var/lib/postgresql/12/main/postmaster.pid)/status VmPeak: 16282784 kB
Для Ubuntu 22.04
grep ^VmPeak /proc/$(sudo head -1 /var/lib/postgresql/14/main/postmaster.pid)/status VmPeak: 16282784 kB
Это максимальный объем памяти, который будет использоваться PostgreSQL. Теперь проверим размер HugePage в Linux.
cat /proc/meminfo | grep -i huge
Вывод команды:
AnonHugePages: 0 kB ShmemHugePages: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB Hugetlb: 0 kB
Теперь можно подсчитать, сколько нужно HugePages. Разделим значение VmPeak на размер HugePage: 16282784 кБ / 2048 кБ = 7950. И создадим отдельный файл, чтобы значения не перезаписались при обновлении системы.
echo "vm.nr_hugepages = 7950" | sudo tee -a /etc/sysctl.d/60-custom.conf
Применим изменения
sudo sysctl -p /etc/sysctl.d/60-custom.conf sudo systemctl restart postgresql
Только не забывайте, что отключив HugePages, PostgreSQL не сможет корректно расположить страницы в памяти. Лучше вообще потом ничего не менять 🙂
Следующий шаг — импорт файлов карт в базу данных
Импорт карт в БД
Для импорта карт в базу данных необходима утилита osm2pgsql. И необходимы права для изменения файлов для пользователя БД
sudo apt install osm2pgsql -y sudo setfacl -R -m u:postgres:rwx /home/osm/
Для импорта нескольких карт их можно объединить программой osmconvert из комплекта утилит osmctools
sudo apt install osmctools
Объединяем скачанные карты
Для примера используем несколько карт скачанных стран
cd /home/osm/ osmconvert <(osmconvert belarus-latest.osm.pbf --out-o5m) \ <(osmconvert finland-latest.osm.pbf --out-o5m) \ <(osmconvert georgia-latest.osm.pbf --out-o5m) \ <(osmconvert kazakhstan-latest.osm.pbf --out-o5m) \ <(osmconvert russia-latest.osm.pbf --out-o5m) \ <(osmconvert ukraine-latest.osm.pbf --out-o5m) -o=merged.pbf
Импортируем карты в базу . Процесс импорта долгий и занимает примерно 5 часов на SSD. Можно предварительно запустить процесс импорта в screen’е. Можно импортировать какой-нибудь город для тестов, это быстрее будет
sudo -u postgres -i osm2pgsql --slim -d gis --hstore --multi-geometry --number-processes 24 \ --tag-transform-script /home/osm/openstreetmap-carto/openstreetmap-carto.lua \ --style /home/osm/openstreetmap-carto/openstreetmap-carto.style -C 32000 /home/osm/merged.pbf
, где
—slim — указывает osm2pgsql создавать “тонкие” таблицы для хранения данных при импорте, а не пытаться хранить все в памяти. —slim также необходим, если мы хотим обновить данные;
-d gis — выбор базы
—hstore — это хранилище ключей и значений, поддерживающее произвольные ключи и значения;
—multi-geometry — указывает osm2pgsql не разбивать мультиполигоны на отдельные полигоны. Это повышает гибкость и устраняет некоторые артефакты визуализации, но немного медленнее.
—number-processes — количество ядер используемых у процессора;
—style — путь к файлу стиля, который сообщает osm2pgsql, какие столбцы создавать;
-С 32000 — размер кэша в мегабайтах. Должен быть примерно 70% от свободной памяти. Учитывайте, что PostgreSQL также использует память для shared_buffers. Общая формула для вычисления кеша такова: (Всего ОЗУ — PostgreSQL shared_buffers) * 0,7
Если в процессе импорта появились следующие или похожие ошибки
PBF error : invalid Blobheader size (> max_blob_header_size)
То, возможно, файл PBF повреждён. Проверьте контрольную сумму файла и сверьте её с той, откуда скачали файл
md5sum russia-latest.osm.pbf
После импорта даём права osm на таблицы базы
psql -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO osm;" -d gis exit
Устанавливаем утилиты для рендеринга карт
Это mod_tile и renderd
mod_tile-это модуль Apache, необходимый для обслуживания тайлов (или плиток), а renderd — сервис рендеринга для получения тайлов OpenStreetMap.
Репозиторий Ubuntu не содержит mod_tile и renderd, так что надо ставить их из OSM PPA.
sudo apt install software-properties-common sudo add-apt-repository ppa:osmadmins/ppa sudo apt install apache2 libapache2-mod-tile renderd -y
Активируем модуль tile
sudo a2enmod tile
Создадим виртуальный хост apache
sudo nano /etc/apache2/sites-available/tileserver_site.conf
И добавим ниже расположенное содержимое в файл
<VirtualHost *:80> ServerName tile.example.com LogLevel info Include /etc/apache2/conf-available/renderd.conf </VirtualHost>
Сохраним файл и включим этот виртуальный сайт
sudo a2ensite tileserver_site.conf
Также включим конфигурацию renderd
sudo a2enconf renderd
Перезапустим apache2
sudo systemctl restart apache2
Генерация стилей Mapnik
Устанавливаем нужные пакеты. В том числе подключим репозиторий для установки npm и nodejs
sudo apt install curl unzip gdal-bin mapnik-utils libmapnik-dev python3-pip -y curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt install -y nodejs
Установим carto через npm и модуль psycopg2 для python
sudo npm install -g carto sudo -H pip3 install psycopg2
Переключимся на пользователя postgres и сформируем файлы границ
sudo -u postgres -i cd /home/osm/openstreetmap-carto/ scripts/get-external-data.py carto project.mml > style.xml psql -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO osm;" -d gis exit
Ставим шрифты для корректного отображения не-ASCII символов
Для Ubuntu 20
sudo apt install ttf-dejavu fonts-noto-cjk fonts-noto-cjk-extra fonts-noto-hinted fonts-noto-unhinted ttf-unifont -y
Для Ubuntu 22
sudo apt install fonts-dejavu-core fonts-noto-cjk fonts-noto-cjk-extra fonts-noto-hinted fonts-noto-unhinted unifont -y
Настраиваем renderd
sudo nano /etc/renderd.conf
В секции [renderd] в опции «num_threads» укажите количество потоков, соответствующее количеству потоков в процессоре вашего сервера
По-умолчанию renderd рендерит плитки только для уровня увеличения равного 18. Опцией MAXZOOM можно увеличить или уменьшить данный параметр.
Итоговое содержимое файла:
[renderd] stats_file=/var/run/renderd/renderd.stats socketname=/var/run/renderd/renderd.sock num_threads=24 tile_dir=/var/cache/renderd/tiles [mapnik] plugins_dir=/usr/lib/mapnik/3.1/input font_dir=/usr/share/fonts/truetype font_dir_recurse=true [default] URI=/osm/ XML=/home/osm/openstreetmap-carto/style.xml DESCRIPTION=This is the standard osm mapnik style ;ATTRIBUTION=©<a href=\"http://www.openstreetmap.org/\">OpenStreetMap</a> and <a href=\"http://wiki.openstreetmap.org/w\ iki/Contributors\">contributors</a>, <a href=\"http://creativecommons.org/licenses/by-sa/2.0/\">CC-BY-SA</a> HOST=tile.example.com ;SERVER_ALIAS=http://a.tile.openstreetmap.org ;SERVER_ALIAS=http://b.tile.openstreetmap.org ;HTCPHOST=proxy.openstreetmap.org
Создадим директорию для настроек сервиса renderd
sudo mkdir /etc/systemd/system/renderd.service.d/
Создадим там конфигурационный файл
sudo nano /etc/systemd/system/renderd.service.d/custom.conf
Сменим имя пользователя
[Service] User=osm
Сменим владельца у директорий
sudo chown osm /run/renderd/ -R sudo chown osm /var/cache/renderd/tiles/ -R
И перезапустим сервисы
sudo systemctl daemon-reload sudo systemctl restart renderd
Проверим в логах всё ли так
sudo journalctl -eu renderd
Настраиваем apache2
sudo nano /etc/apache2/sites-available/tileserver_site.conf
и указываем
ServerName tile.example.com
Перезапускаем apache2
sudo systemctl restart apache2
Настраиваем отображение карт в браузере
Теперь у нас есть работающий сервер OSM. Однако, для отображения карты на других серверах нужно использовать библиотеку карт JavaScript. В этой инструкции я создаю веб-карту на том же сервере, но ничто не мешает сделать это на другом сервере.
Есть две бесплатные библиотеки карт JavaScript с открытым исходным кодом, которые вы можете использовать для своего сервера плиток: OpenLayer и Leaflet. Преимущество Leaflet в том, что она проста в использовании, и карта будет удобна в использовании на мобильных устройствах
Но если скачать Leaflet не получается, то используйте OpenLayer или cкачайте Leaflet по ссылке.
Используем OpenLayer
Редакция от 26.06.2024
Раньше использование OpenLayer было простым — качаешь дистрибутив, пишешь html файл и кидаешь всё это в директорию, откуда чти данные читает веб-сервер. Однако на сайте openlayer написано, что для комфортной работы используйте пакет npm под названием ol.
В этом случае будет немного больше действий для запуска веб-рендерера, зато и возможностей настройки будет больше. Итак, выполняем в консоли
cd ~
npm create ol-app tile-app
cd tile-app
В домашней директории создастся папка с именем проекта. Внутри редактируем файл main.js
nano main.js
import './style.css';
import {Map, View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import { transform } from 'ol/proj';
var map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM({
url: 'https://tile.example.com/osm/{z}/{x}/{y}.png'
})
})
],
view: new View({
center: transform([30, 60], 'EPSG:4326', 'EPSG:3857'),
zoom: 8
}),
});
Функция transform преобразует координаты в стандартные с широтой и долготой. Координаты указаны на Санкт-Петербург.
Затем запустите сборку и перенесите сборочные файлы в директорию, обслуживаемую веб-сервером
npm run build && sudo rm -r /var/www/html/* && sudo cp -r dist/* /var/www/html/
Карты теперь доступны по адресу https://tile.example.com
Это простейший пример использования OpenLayer. На сайте есть подробная документация — https://openlayers.org/en/latest/examples/
Используем Leaflet
cd /var/www/html sudo wget http://cdn.leafletjs.com/leaflet/v1.7.1/leaflet.zip или sudo wget https://kurazhov.ru/programs/leaflet.zip sudo unzip leaflet.zip
Создаём файл показа карты
sudo nano /var/www/html/index.html
<html> <head> <meta charset="UTF-8"> <title>OSM Tile</title> <link rel="stylesheet" type="text/css" href="leaflet.css"/> <script type="text/javascript" src="leaflet.js"></script> <style> #map{width:100%;height:100%} </style> </head> <body> <div id="map"></div> <script> var map = L.map('map').setView([60,31.0],9); L.tileLayer( 'http://tile.example.com/osm/{z}/{x}/{y}.png',{maxZoom:18}, ).addTo(map); </script> </body> </html>
Карты доступны по адресу http://tile.example.com
Дополнение: (2024.02.12)
Для пререндера тайлов, чтобы пользователь не ждал загрузки карты каждый раз при увеличении или уменьшении масштаба можно запустить команду render_list. С помощью данной утилиты можно указать масштабный уровень и диапазоны x и y координат тайлов и осуществить предварительный рендеринг.
render_list --all --max-zoom=9 --min-zoom=1 --num-threads=24
Для того, чтобы не было серых тайлов из-за того, что renderd ещё не успел их подготовить, в модуле /etc/apache2/conf-enabled/renderd.conf можно привести следующие параметры к таким значениям:
ModTileRequestTimeout 30 ModTileMissingRequestTimeout 100
Дополнение:
Для ускорения рендеринга можно воспользоваться скриптом в консоли postgres
-- These are indexes for rendering performance with OpenStreetMap Carto. -- This file is generated with scripts/indexes.py CREATE INDEX planet_osm_line_ferry ON planet_osm_line USING GIST (way) WHERE route = 'ferry' AND osm_id > 0; CREATE INDEX planet_osm_line_label ON planet_osm_line USING GIST (way) WHERE name IS NOT NULL OR ref IS NOT NULL; CREATE INDEX planet_osm_line_river ON planet_osm_line USING GIST (way) WHERE waterway = 'river'; CREATE INDEX planet_osm_line_waterway ON planet_osm_line USING GIST (way) WHERE waterway IN ('river', 'canal', 'stream', 'drain', 'ditch'); CREATE INDEX planet_osm_point_place ON planet_osm_point USING GIST (way) WHERE place IS NOT NULL AND name IS NOT NULL; CREATE INDEX planet_osm_polygon_admin ON planet_osm_polygon USING GIST (ST_PointOnSurface(way)) WHERE name IS NOT NULL AND boundary = 'administrative' AND admin_level IN ('0', '1', '2', '3', '4'); CREATE INDEX planet_osm_polygon_military ON planet_osm_polygon USING GIST (way) WHERE (landuse = 'military' OR military = 'danger_area') AND building IS NULL; CREATE INDEX planet_osm_polygon_name ON planet_osm_polygon USING GIST (ST_PointOnSurface(way)) WHERE name IS NOT NULL; CREATE INDEX planet_osm_polygon_name_z6 ON planet_osm_polygon USING GIST (ST_PointOnSurface(way)) WHERE name IS NOT NULL AND way_area > 5980000; CREATE INDEX planet_osm_polygon_nobuilding ON planet_osm_polygon USING GIST (way) WHERE building IS NULL; CREATE INDEX planet_osm_polygon_water ON planet_osm_polygon USING GIST (way) WHERE waterway IN ('dock', 'riverbank', 'canal') OR landuse IN ('reservoir', 'basin') OR "natural" IN ('water', 'glacier'); CREATE INDEX planet_osm_polygon_way_area_z10 ON planet_osm_polygon USING GIST (way) WHERE way_area > 23300; CREATE INDEX planet_osm_polygon_way_area_z6 ON planet_osm_polygon USING GIST (way) WHERE way_area > 5980000; CREATE INDEX planet_osm_roads_admin ON planet_osm_roads USING GIST (way) WHERE boundary = 'administrative'; CREATE INDEX planet_osm_roads_admin_low ON planet_osm_roads USING GIST (way) WHERE boundary = 'administrative' AND admin_level IN ('0', '1', '2', '3', '4'); CREATE INDEX planet_osm_roads_roads_ref ON planet_osm_roads USING GIST (way) WHERE highway IS NOT NULL AND ref IS NOT NULL;
Источники информации:
— https://www.linuxbabe.com/ubuntu/openstreetmap-tile-server-ubuntu-20-04-osm
— https://raw.githubusercontent.com/gravitystorm/openstreetmap-carto/master/indexes.sql
— https://wiki.gis-lab.info/w/Создание_тайлового_сервера_на_основе_данных_OpenStreetMap_и_mod_tile
Да, в ближайшее время отредактирую, как только смогу. Отпишусь и в комментариях и в записи
Отредактировал часть про OpenLayer. Немного усложнился процесс развёртывания
Спасибо за статью!
Хочу добавить один момент.
В последней версии ubuntu папка для сокетов /run/renderd создается по умолчанию от имени пользователя _renderd. Сервис renderd, который запускается от имени osm писать в нее не может.
Чтобы это победить, отредактировал файл /var/lib/tmpfiles.d/renderd.conf поменяв _renderd на osm.
Для системы init.d в сценарии запуска есть создание папки с сокетами и задание владельца. Надо только RUNASUSER задать.
При установке renderd действительно создаёт директорию в /run. Это, по-моему, и делается init.d скриптами. Однако связь renderd с БД, где лежат данные такова, что при работе с БД вызывается пользователь, под которым работает renderd. При этом postgres закономерно выдаёт сообщение «Postgis Plugin: connection to server on socket «/var/run/postgresql/.s.PGSQL.5432» failed: FATAL: role «_renderd» does not exist»
Для этого renderd запускается от имени osm, чтобы корректно работать с БД. И соответственно нужны правки с правами на директории /run/renderd и /var/cache/renderd/tiles/
Init.d на Ubuntu права на директории не меняет. Так что легче поменять пользователя.
not found
Пытался поставить по инструкции OSM на Ubuntu 22.04
Сайт через Leflet в результате рисует пустую страничку.
Renderd валит кучу варнингов вида:
Mapnik LOG> 2023-03-03 13:10:31: warning: unable to find face-name ‘Noto Emoji Regular’ in FontSet ‘fontset-1’
на все шрифты, видимо
Куда копать?
Статья по установке шрифтов для OSM — тут