Приветствую, хабравчане!
Это моя первая статья, и она посвящена GeoServer`у и его использованию в web-картах.
Статья ориентирована на людей, имеющих опыт публикации своих картографических проектов посредством HTML, CSS и JavaScript, и столкнувшихся с необходимостью хотя бы время от времени обновлять отображаемые данные. Статья будет полезна также и для тех, кто хочет узнать о более продвинутых методах работы с геоданными в web.
Мой опыт в области создания web-геосервисов невелик, однако я решил им поделиться ввиду крайне малого объёма информации по теме как в русскоязычном пространстве интернета, так и в сети в целом.
На мой взгляд существует информационная пропасть между начальным уровнем создания карт в web`е (создайте страницу с попапом по клику, загрузите свой GeoJSON) и рассмотрением тонкостей работы полноценных web-геосервисов (как хранить кэш тайлов, отобразить OSM на весь мир и т.д.). Частичку этой пропасти я и хочу постараться заполнить.
Статья нацелена больше на далёких от темы ГИС-специалистов и связанных с ними профессий, нежели на web-разработчиков, и носит прикладной характер. В ней будет рассмотрено:
Зачем нужен GeoServer?
Покупка домена, аренда сервера и их связка
Публикация собственного сайта с картой
Установка 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) и могут быть созданы двумя основными способами:
Загрузкой данных в Mapbox Studio
Использованием открытой спецификации MVT в различных программах или расширениях.
Первый вариант проще, но требует повторной загрузки данных при их изменении, что приводит к изменению ссылок и ID, вызывая необходимость корректировок на сайте. Если ваши данные не конфиденциальны и не нуждаются в частом обновлении, этот вариант может быть приемлем. Я же продолжу про второй.
GeoServer — это open-source серверное программное обеспечение для предоставления геопространственных данных. Оно является решением, позволяющим как соответствовать стандартам OGC и предоставлять векторные данные в виде плиток, так и упрощающим процесс обновления отображаемых данных. В качестве источников используются форматы: GeoPackage, PostGIS Database, Shapefile, GeoJSON, KML, GeoTIFF, ArcGrid и другие. Выходные данные же передаются по протоколам: WMTS, WCS, WFS и WMS, удовлетворяющим стандартам OGC.
Работа с GeoServer происходит в веб-интерфейсе. Через него можно загрузить данные, применить для них стили в формате SLD, просмотреть результат через OpenLayers, задать формат изображений тайлов, включить для них кэширование и многое другое.
![Интерфейс GeoServer Интерфейс GeoServer](https://webcf.waybackmachine.org/web/20240608210202/https://habrastorage.org/getpro/habr/upload_files/a7d/8f2/586/a7d8f25862373c78aecfe57e2c11a30c.png)
Существуют и альтернативы в виде: 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
— теперь создадим свой файл сайта и пропишем туда базовую структуру для проверки работоспособности.
<!DOCTYPE html><html lang="ru">
<head>
<title>pushkino-maps</title>
<meta charset="utf-8">
</head>
<body>
<h1>pushkino-maps</h1>
</body>
</html>
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 [email protected]:~
а потом уже создаём папку для хранения ключей и переносим их туда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 [email protected]:~
— с помощью команды 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`а.
Поскольку настройка групп нам не нужна, то можно остановиться на следующих пунктах:
sudo apt update
sudo apt upgrade
java --version
— проверяем есть у нас уже Java (если у вас чистая операционка, то точно нет)sudo apt install openjdk-11-jdk -y
— устанавливаем Java именно 11-ой версии, новее работают нестабильноwget <https://sourceforge.net/projects/geoserver/files/GeoServer/2.25.0/geoserver-2.25.0-bin.zip
> — скачиваем GeoServersudo mkdir /usr/share/geoserver
— создаём папку, где он будет храниться. Общепринято по данной директорииsudo apt install unzip
— скачиваем разархиваторsudo unzip -d /usr/share/geoserver/ geoserver-2.25.0-bin.zip
— разархивируем в ранее созданную директориюsudo rm geoserver-2.25.0-bin.zip
— удаляем изначальный архивecho "export GEOSERVER_HOME=/usr/share/geoserver" >> ~/.profile
. ~/.profile
— создаём переменную чтобы впоследствии обращаться короче к директории, например: $GEOSERVER_HOME/bin/startup.shsudo chown -R USER_NAME /usr/share/geoserver/
— для изменения владельца директории. Честно говоря не уверен нужно ли это когда один пользователь. Но в инструкции GeoServer`а это есть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:
wget <https://sourceforge.net/projects/geoserver/files/GeoServer/2.25.0/extensions/geoserver-2.25.0-vectortiles-plugin.zip
>sudo unzip -d /usr/share/geoserver/webapps/geoserver/WEB-INF/lib geoserver-2.25.0-vectortiles-plugin.zip
sudo rm geoserver-2.25.0-vectortiles-plugin.zip
Перезапуск GeoServer`а
Подробнее о включении расширения для желаемых слоёв можно прочитать здесь.
И всё было бы сладко да гладко, загружай свои файлы, добавляй ссылку в код сайта, но…
Решение проблем с GeoServer`ом №2
Но GeoServer работает на HTTP, а сайт на HTTPS блокирует такой контент, выдавая ошибку:
Mixed Content: The page at 'blob:<URL>' was loaded over HTTPS, but requested an insecure resource '<URL>'. This request has been blocked; the content must be served over HTTPS.
Поэтому, долго мучаясь и опираясь в основном на эту инструкцию Using NGINX to put Geoserver HTTPS, пришёл к следующему решению:
К нашему конфигу pushkino-maps.conf дописываем код ниже
(location / { try_files $uri $uri/ =404; } оставляем нетронутым)
# Проксирование запросов к GeoServer
location /geoserver {
proxy_pass <http://127.0.0.1:8080/geoserver>;
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;
}
Geoserver Web Page — Настройки — Глобальные (или же /usr/share/geoserver/data_dir/global.xml):
Базовый URL-адрес прокси-сервера: https://pushkino-maps.ru
Использовать заголовки для URL прокси ☑В файл /usr/share/geoserver/webapps/geoserver/WEB-INF/web.xml добавить:
<context-param>
<param-name>GEOSERVER_CSRF_WHITELIST</param-name>
<param-value>pushkino-maps.ru</param-value>
</context-param>
и изменить PROXY_BASE_URL на:
<context-param>
<param-name>PROXY_BASE_URL</param-name>
<param-value>https://pushkino-maps.ru/geoserver</paramvalue>
</context-param>
Теперь наш 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: [
"<https://pushkino-maps.ru/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.1.1&LAYER=push_how_old:buildings_pushkino_how_old_wmts&STYLE=&TILEMATRIX=EPSG:900913:{z}&TILEMATRIXSET=EPSG:900913&FORMAT=application/vnd.mapbox-vector-tile&TILECOL={x}&TILEROW={y}>",
],
bounds: [37.78089132, 55.96388819, 37.93968874, 56.060285621],
});
Поздравляю, вы вновь великолепны, и теперь у вас есть собственный сайт с web-картой, использующей данные с GeoServer`а!!!
На этом всё. Буду благодарен за ваши замечания и дополнения!