Публикация web-карт с GeoServer: от установки до интеграции с Mapbox GL JS

Приветствую, хабравчане!

Это моя первая статья, и она посвящена GeoServer`у и его использованию в web-картах.

Статья ориентирована на людей, имеющих опыт публикации своих картографических проектов посредством HTML, CSS и JavaScript, и столкнувшихся с необходимостью хотя бы время от времени обновлять отображаемые данные. Статья будет полезна также и для тех, кто хочет узнать о более продвинутых методах работы с геоданными в web.

Мой опыт в области создания web-геосервисов невелик, однако я решил им поделиться ввиду крайне малого объёма информации по теме как в русскоязычном пространстве интернета, так и в сети в целом.

На мой взгляд существует информационная пропасть между начальным уровнем создания карт в web`е (создайте страницу с попапом по клику, загрузите свой GeoJSON) и рассмотрением тонкостей работы полноценных web-геосервисов (как хранить кэш тайлов, отобразить OSM на весь мир и т.д.). Частичку этой пропасти я и хочу постараться заполнить.

Статья нацелена больше на далёких от темы ГИС-специалистов и связанных с ними профессий, нежели на web-разработчиков, и носит прикладной характер. В ней будет рассмотрено:

  1. Зачем нужен GeoServer?

  2. Покупка домена, аренда сервера и их связка

  3. Публикация собственного сайта с картой

  4. Установка GeoServer и его использование с Mapbox GL JS.

1. Зачем нужен GeoServer?

Введение

Предположим, благодаря обширному количеству информации в интернете, вам удалось создать свою web-карту или картографический web-сервис с помощью таких популярных JS-библиотек, как Leaflet, OpenLayers и Mapbox.

Предположим также, что вы сумели разместить свой проект в сети, а не только на своей локальной машине. Возможно, с помощью GitHub Pages, а может даже и хостинга! Вот только как обновлять отображаемые данные?

Если ваши данные растрового формата, то они, скорее всего, хранятся:

  • локально в директории с HTML-файлом;

  • в арендованном облачном хранилище, например, Yandex.Cloud Object Storage.

Таким образом, для обновления растровых данных вам необходимо сперва создать тайлы и затем обновить их в директории. Это вполне приемлемо, но процесс можно упростить.

Если ваши данные векторного формата, то они, вероятно, подгружаются в виде JSON/GeoJSON локально или удаленно из базы данных. Этот подход приемлем при небольшом объёме данных, когда скорость интернет-соединения позволяет скачать весь GeoJSON. В противном случае лучше использовать векторные тайлы. Кроме того, передача географических данных в формате JSON не соответствует стандартам Open Geospatial Consortium (OGC), а использование тайлов — да.

Векторные тайлы имеют формат Mapbox Vector Tiles (MVT) и могут быть созданы двумя основными способами:

  1. Загрузкой данных в Mapbox Studio

  2. Использованием открытой спецификации MVT в различных программах или расширениях.

Первый вариант проще, но требует повторной загрузки данных при их изменении, что приводит к изменению ссылок и ID, вызывая необходимость корректировок на сайте. Если ваши данные не конфиденциальны и не нуждаются в частом обновлении, этот вариант может быть приемлем. Я же продолжу про второй.

GeoServer — это open-source серверное программное обеспечение для предоставления геопространственных данных. Оно является решением, позволяющим как соответствовать стандартам OGC и предоставлять векторные данные в виде плиток, так и упрощающим процесс обновления отображаемых данных. В качестве источников используются форматы: GeoPackage, PostGIS Database, Shapefile, GeoJSON, KML, GeoTIFF, ArcGrid и другие. Выходные данные же передаются по протоколам: WMTS, WCS, WFS и WMS, удовлетворяющим стандартам OGC.

Работа с GeoServer происходит в веб-интерфейсе. Через него можно загрузить данные, применить для них стили в формате SLD, просмотреть результат через OpenLayers, задать формат изображений тайлов, включить для них кэширование и многое другое.

Интерфейс GeoServer

Интерфейс GeoServer

Существуют и альтернативы в виде: MapServer, ArcGIS Server и QGIS Server. ArcGIS Server является проприетарным ПО и поэтому не рассматривается. QGIS Server и Mapserver мне показались то ли устаревшими, то ли крайне редко используемыми продуктами, поэтому выбран был именно GeoServer.

Также стоит упомянуть OpenMapTiles в сочетании с TileServer GL. Эти инструменты не являются полноценными серверными приложениями, однако также позволяют создавать и отображать векторные тайлы. Однако, как мне это видеться, данное решение больше ориентировано на отображение данных OpenStreetMap в качестве подложки, а не для собственных данных.

Окей, я в деле

Если вы ранее не работали с GeoServer, то для тестирования его работы можно сперва установить его на свой ПК и подключить к локально хранящемуся сайту. YouTube вам в помощь.

Однако, скорее всего, вы хотите опубликовать свой сайт в интернете, и, следовательно, он не сможет пользоваться данными с вашего локального GeoServer`а. Для решения этой проблемы можно пойти двумя путями:

Поскольку в своих работах я не использую конфиденциальные данные и не желаю приобретать для них отдельное железо и статический IP, то воспользуюсь услугами аренды. Весь дальнейший процесс я буду описывать для своего сайта pushkino-maps.ru. Мне кажется, так будет понятнее и нагляднее, чем использование условного example.com и случайного IP-адреса.

2. Покупка домена, аренда сервера и их связка

Покупка и регистрация домена

Первым делом необходимо приобрести домен, по которому будет располагаться ваш сайт с web-картой. Не для всех этот шаг будет обязательным, однако для публичного доступа к сайту вам это потребуется.

Существуют десятки сервисов, предоставляющих услуги по покупке доменных имён и все они примерно одинаковые. Я решил воспользоваться наиболее крупным и вызывающим доверие, а именно рег.ру. Собственно, домен я выбрал pushkino-maps.ru.
При покупке домена предлагают ряд дополнительных продуктов, все они, кроме SSL-сертификата не нужны. В большинстве сервисов он бесплатный первые месяцы, данный случай не исключение. Да, существует возможность и самому установить этот сертификат бесплатно, например, с помощью Let`s Encrypt. Есть ли разница между платными и бесплатными сертификатами, я сказать не могу, собственно поэтому и решил воспользоваться предлагаемой регистратором опцией.

Выбор конфигурации и аренда сервера

Поскольку нашей целью является использование GeoServer`а, то использование хостинга нам не подойдёт. На них можно пользоваться только заранее установленным набором ПО, таким как PostgreSQL, Django, PHP и другим. Поэтому нам нужен не хостинг, а VPS-сервер.

Есть так же большое количество сервисов для аренды VPS-серверов. Я воспользовался VK Cloud, исключительно потому, что он недавно запустился и предлагал большое количество бонусных рублей, которые покрывали аж 3 месяца работы. В VK Cloud сервер нужного нам типа называется «Инстанс».

Конфигурация инстанса:

  • железо всё на минимуме, 10ГБ хватит;

  • тип диска — SSD (ибо разница с HDD всего 80 рублей в месяц);

  • операционная система — Ubuntu 22 (просто потому что ранее с ней сталкивался и является одной из самых популярных);

  • сеть — внешняя сеть интернет;

  • ключ виртуальной машины — создать новый ключ;

  • настройки Firewall — default, shh+www.

Почему default, shh+www?

Из описания настроек в VK Cloud:

  • default — Входящий трафик разрешён только от инстансов, имеющих такую же группу безопасности. Трафик из сети Интернет не разрешён. Любой исходящий трафик разрешён;

  • all — Разрешён любой входящий и исходящий трафик;

  • ssh — Разрешён входящий трафик на SSH (порт 22);

  • ssh+www — Разрешён входящий трафик на SSH (порт 22) и HTTP (порты 80 и 443).

Но, честно говоря, мне кажется, что данные пояснения имеют мало связи с реальностью… Ибо при использовании ssh+www или ssh+www+all я не мог подключиться к сети, скачать апдейты или выполнить команду ping. А вот сочетание default+ssh+www позволило подключиться к интернету (default+ssh не проверял).

IP-adress полученной виртуальной машины — 90.156.216.75

Настройка связи между Ubuntu и доменом

Для связи IP с доменом необходимо в личном кабинете выбранного вами регистратора, в данном случае рег.ру, зайти в настройки купленного домена и добавить ресурсные записи:
А @ — 90.156.216.75
AAAA @ — fe80:: f816:3eff: fe16:562b (пока мы этого не знаем, но сможем узнать, когда запустим Ubuntu и выполним командуifconfig)
CNAME WWW — pushkino-maps.ru

3. Публикация собственного сайта с картой

Установка Nginx и проверка тестового сайта

Следующий шаг — подключение к купленной машине на Ubuntu. О том, как это сделать, можете посмотреть инструкцию на сайте поставщика, в моём случае VK Cloud.

Для работы нашего сайта необходим web-сервер. Между Apache и Nginx выбор пал на Nginx, ибо показался современнее.
sudo apt update -y
sudo apt upgrade
sudo apt install nginx

По умолчанию сайты на Nginx размещаются в папке /var/www/, и после установки там лежит базовая HTML-страница. Не обязательно размещать свои сайты именно там, но для удобства и простоты почему бы и нет.

sudo mkdir /var/www/pushkino-maps — создадим папку для своего сайта (то ли желательно, то ли обязательно назвать так же как и купленный вами домен).

sudo nano /var/www/pushkino-maps/index.html — теперь создадим свой файл сайта и пропишем туда базовую структуру для проверки работоспособности.



    pushkino-maps
    


    

pushkino-maps

Nginx работает по двум папкам:

  • /etc/nginx/sites-available, где хранятся конфигурационные файлы сайтов

  • /etc/nginx/sites-enabled, куда присоединяются уже созданные конфиги (включение и выключение сайтов)

Создадим конфигурационный файл для сайта и пропишем в нём базовые правила

sudo nano /etc/nginx/sites-available/pushkino-maps.conf

server {
    listen 80;
    listen [::]:80;
    server_name pushkino-maps.ru www.pushkino-maps.ru;

    root /var/www/pushkino-maps;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

Следом

sudo ln -s /etc/nginx/sites-available/pushkino-maps.conf /etc/nginx/sites-enabled — включаем наш сайт (то есть создаём ссылку на файл конфигурации).
sudo nginx -t — проверяем конфигурацию Nginx, что ничего не поломалось. Должно быть две успешных строки.
sudo systemctl restart nginx — перезапускаем Nginx для применения изменений.

Переходим на наш сайт, в моём случае http://pushkino-maps.ru. Именно HTTP, ибо HTTPS мы ещё не настроили. Если всё было настроено верно, то по адресу должна быть наша простенькая html-страничка.

Настройка конфига под HTTPS

Для настройки HTTPS перво-наперво нужно привести ключи к определённому формату. Как это сделать, можно прочитать у поставщика домена. В моём случае, для Nginx, инструкция находится здесь (пункты 1 и 2).

После формирования ключей их необходимо перенести с локальной машины (в моём случае Windows 11) на удалённую Ubuntu:

Команда csp выполняется через cmd Windows, в среде самой Windows, а не в Ubuntu!

scp -i <путь к ssh-ключу> <имя пользователя>@<внешний IP-адрес виртуальной машины>:/путь/на/ubuntu

Так как мы заходим не под root`ом и прав на запись в /etc/nginx/ у нас нет, то в качестве первичной папки выбираем домашний каталог:
scp -i <путь к ssh-ключу>.crt ubuntu@90.156.216.75:~
а потом уже создаём папку для хранения ключей и переносим их туда
sudo mkdir /etc/nginx/ssl
sudo mkdir /etc/nginx/ssl/pushkino-maps
sudo mv ~/ssl-key.crt /etc/nginx/ssl/pushkino-maps

Осталось только изменить конфиг сайта на:

server {
    listen 80;
    listen [::]:80;
    server_name pushkino-maps.ru www.pushkino-maps.ru;

    # Перенаправление на HTTPS
    return 301 https://pushkino-maps.ru$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name www.pushkino-maps.ru;

    # Перенаправление с www-ссылки на ссылку без www
    return 301 https://pushkino-maps.ru$request_uri;
    
    ssl_certificate /путь/к/вашему/ssl-сертификату.crt;
	ssl_certificate_key /путь/к/вашему/ключу/ssl-сертификата.key;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name pushkino-maps.ru;

    ssl_certificate /путь/к/вашему/ssl-сертификату.crt;
	ssl_certificate_key /путь/к/вашему/ключу/ssl-сертификата.key;

    root /var/www/pushkino-maps;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

И вновь перезапустить Nginx (sudo systemctl restart nginx)

Ура, сайт работает на HTTPS!

Перенос сайта

Пока перенесём сайт, который не зависит от GeoServer`а, и в котором после лишь заменим ссылку на данные.

sudo rm -r /var/www/pushkino-maps — удаляем папку, где хранится наш сайт-заглушка;
scp -i <путь к ssh-ключу>.crt -r C:\Users\ilja2\OneDrive\Desktop\how_old_is_pushkino\pushkino-maps ubuntu@90.156.216.75:~ — с помощью команды scp переносим папку из Windows;
sudo mv ~/pushkino-maps /var/www — перемещаем её в нужный каталог;
sudo systemctl restart nginx — перезапускаем Nginx…

Поздравляю, вы великолепны!!!

В дальнейшем для удобства переноса файлов и их редактирования рекомендую воспользоваться WinSCP.

4. Установка GeoServer и его использование с Mapbox GL JS

Установка GeoServer на Ubuntu

Установка GeoServer на Ubuntu проста и хорошо описана на OSM Wiki и дополнена в инструкции GeoServer`а.

Поскольку настройка групп нам не нужна, то можно остановиться на следующих пунктах:

  1. sudo apt update

  2. sudo apt upgrade

  3. java --version — проверяем есть у нас уже Java (если у вас чистая операционка, то точно нет)

  4. sudo apt install openjdk-11-jdk -y — устанавливаем Java именно 11-ой версии, новее работают нестабильно

  5. wget > — скачиваем GeoServer

  6. sudo mkdir /usr/share/geoserver — создаём папку, где он будет храниться. Общепринято по данной директории

  7. sudo apt install unzip — скачиваем разархиватор

  8. sudo unzip -d /usr/share/geoserver/ geoserver-2.25.0-bin.zip — разархивируем в ранее созданную директорию

  9. sudo rm geoserver-2.25.0-bin.zip — удаляем изначальный архив

  10. echo "export GEOSERVER_HOME=/usr/share/geoserver" >> ~/.profile

  11. . ~/.profile — создаём переменную чтобы впоследствии обращаться короче к директории, например: $GEOSERVER_HOME/bin/startup.sh

  12. sudo chown -R USER_NAME /usr/share/geoserver/ — для изменения владельца директории. Честно говоря не уверен нужно ли это когда один пользователь. Но в инструкции GeoServer`а это есть

  13. cd /usr/share/geoserver/bin startup.sh или $GEOSERVER_HOME/bin/startup.sh — запуск Geoserver`а.

Всё, Geoserver запущен на http://<внешний IP-адрес виртуальной машины>:8080/geoserver

Выйти из окна GeoServer`а и приостановить его работу — Ctrl+C (а вообще $GEOSERVER_HOME/bin/shutdown.sh).
Чтобы оставить GeoServer включённым, но иметь возможность писать другие команды в Ubuntu, потребуется второе окно.

Чтобы прервать подключение по SHH и оставить GeoServer включённым необходимо ввести screen -S geoserver, запустить GeoServer $GEOSERVER_HOME/bin/startup.sh и после того как GeoServer запустится, отсоединиться от сеанса, нажав Ctrl + A и Ctrl + D.

Рекомендуется также сменить пароль и мастер-пароль со стандартной пары admin — geoserver.

Решение проблем с GeoServer`ом №1

Однако зайти на http:/90.156.216.75:8080/geoserver сейчас не получится, ибо порт 8080 у нас закрыт. Открыть его можно путём изменения настроек Firewall`а в VK Cloud на default, shh+www, all.

В целом эту часть можно проделать и не через кабинет VK Cloud, а с помощью утилит ufw, iptables и других, но поскольку я не знаю, какой утилитой это делает VK Cloud, то лучше без должных навыков одно поверх другого не использовать.

Расширение для работы с MVT

В рамках своего проекта я использую векторные данные и мне необходимо взаимодействовать с ними на сайте, а следовательно, необходимы векторные тайлы. Для использования данных из GeoServer`а в качестве векторных тайлов необходимо установить расширение Vector Tiles:

  1. wget >

  2. sudo unzip -d /usr/share/geoserver/webapps/geoserver/WEB-INF/lib geoserver-2.25.0-vectortiles-plugin.zip

  3. sudo rm geoserver-2.25.0-vectortiles-plugin.zip

  4. Перезапуск GeoServer`а

Подробнее о включении расширения для желаемых слоёв можно прочитать здесь.

И всё было бы сладко да гладко, загружай свои файлы, добавляй ссылку в код сайта, но…

Решение проблем с GeoServer`ом №2

Но GeoServer работает на HTTP, а сайт на HTTPS блокирует такой контент, выдавая ошибку:
Mixed Content: The page at 'blob: ' was loaded over HTTPS, but requested an insecure resource ''. This request has been blocked; the content must be served over HTTPS.

Поэтому, долго мучаясь и опираясь в основном на эту инструкцию Using NGINX to put Geoserver HTTPS, пришёл к следующему решению:

  1. К нашему конфигу pushkino-maps.conf дописываем код ниже
    (location / { try_files $uri $uri/ =404; } оставляем нетронутым)

  # Проксирование запросов к GeoServer
    location /geoserver {
            proxy_pass ;
            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_redirect off;
         }
  1. Geoserver Web Page — Настройки — Глобальные (или же /usr/share/geoserver/data_dir/global.xml):
    Базовый URL-адрес прокси-сервера: https://pushkino-maps.ru
    Использовать заголовки для URL прокси ☑

  2. В файл /usr/share/geoserver/webapps/geoserver/WEB-INF/web.xml добавить:


  GEOSERVER_CSRF_WHITELIST
  pushkino-maps.ru

и изменить PROXY_BASE_URL на:

    
      PROXY_BASE_URL
      https://pushkino-maps.ru/geoserver
    

Теперь наш Geoserver обитает по адресу https://90.156.216.75/geoserver или же https://pushkino-maps.ru/geoserver и всё должно прекрасно работать!

Причём при подключении слоя обязательно прописывать ссылку с доменом, а не с IP, дабы не встретиться с CORS-ошибками. Вот как выглядит подключение посредством Mapbox GL JS:

map.addSource("buildings_pushkino_how_old", {
          type: "vector",
          tiles: [
            "",
          ],
          bounds: [37.78089132, 55.96388819, 37.93968874, 56.060285621],
        });

Поздравляю, вы вновь великолепны, и теперь у вас есть собственный сайт с web-картой, использующей данные с GeoServer`а!!!

На этом всё. Буду благодарен за ваши замечания и дополнения!

© Habrahabr.ru