Свой собственный облачный MQTT брокер с поддержкой WebSockets, сертификатами LetsEncrypt, мониторингом и визуализацией в Grafana и сохранением данных в Influx. Бесплатно и навсегда

Уровень сложности для продвинутого пользователя ПК: средний. Потребуются навыки работы с командной строкой linux через SSH, возможно понадобится изучение технической документации на английском языке. Хочу предупредить, что эта статья не туториал для начинающих, в котором достаточно скопировать все команды из статьи в консоль и все заработает. То, что мы будем делать, потянет на тестовое задание для начинающего DevOps инженера. Может быть я упустил что-то очевидное для меня и Вам придется немного поработать напильником. Ориентировочное время: от 1 часа до бесконечности, в зависимости от Ваших навыков и желания учиться.

TLDR; Получаем бесплатный VPS сервер, бесплатный домен 2 уровня и запускаем docker контейнеры: portainer, nginx, certbot, RabbitMQ, Grafana, Prometheus, Telegraf, InfluxDB с помощью docker-compose файла, который я заботливо приготовил для Вас.

Для домашней автоматизации часто необходим MQTT брокер, который должен быть доступен из интернета. Поднимать брокер на RaspberryPi и пробрасывать порты во внешний мир через домашний роутер — можно, но это далеко не идеальное решение (еще и валидные сертификаты при этой схеме непросто получить), а вот построить bridge (мост) между домашним брокером и облачным, чтобы иметь доступ и из дома и из любой точки мира и не оказаться в «умершем умном доме» при отсутствии интернета — неплохое решение.

Раньше в качестве облачного бесплатного брокера использовали CloudMQTT.com, но недавно эта компания прекратила регистрацию новых бесплатных инстансов и оставила возможность только платной регистрации.

Чаще всего, в качестве MQTT брокера разворачивают mosquitto — это отличный быстрый брокер, не требующий излишних вычислительных ресурсов. Но есть у него и недостатки — список пользователей и их права доступа необходимо прописывать в текстовых файлах. Я предлагаю Вам пострелять из пушки по воробьям и использовать в качестве MQTT сервера брокер сообщений RabbitMQ, который имеет плагин MQTT в базовой поставке и простой WEB интерфейс для настройки и управления пользователями.

Также мы будем использовать Prometheus плагин для RabbitMQ, для мониторинга состоянии брокера и ресурсов, которые он использует.

RabbitMQ написан на языке erlang, позволяет объединять брокеры в кластер, успешно используется во многих коммерческих проектах.

RabbitMQ имеет и другие замечательные возможности (очереди, например), но описание этих возможностей выходит за рамки данной статьи и я предлагаю Вам самостоятельно их изучить, если будет интересно.

Для полноценного использования MQTT мы настроим автоматическое получение бесплатных SSL(TLS) сертификатов LetsEncrypt, подключение WebSockets (MQTT over WebSockets), настроим WEB сервер nginx, так что сделать еще и собственный сайт — дело пяти дополнительных минут.

Современные DevOps инженеры не представляют свою работу без контейнеров, поэтому и мы будем использовать best practices — развернем весь необходимый софт в контейнерах. Я не фанатичный линуксоид, который признает исключительно командную строку в терминале, поэтому для обычных людей установим Portainer — удобный WEB интерфейс для управления docker контейнерами.

Раз уж мы используем Prometheus для мониторинга брокера, то установим и node-exporter для мониторинга нашего VPS сервера.

Также мы, легким движением руки, реализуем задачу сохранения MQTT сообщений в базе данных InfluxDB, используя для этого Telegraf.

Вишенкой на торте будет визуализация данных в одном из самых популярных современных продуктов — Grafana. Там мы увидим статистику и нашего VPS сервера и статистику RabbitMQ и сами данные, полученные по MQTT. По факту, мы сделаем собственный универсальный dashboard (точнее, можем сделать множество наборов панелей, в зависимости от задач), переплюнув популярные облачные сервисы.

Grafana: мониторинг VPS

Grafana: мониторинг RabbitMQ

Grafana: визуализация MQTT данных

Получаем VPS сервер бесплатно и навсегда

Здесь я не буду останавливаться подробно — Вы сможете без труда найти статьи как это сделать. Мне понравились VPS, которые предоставляет Oracle — они дают две виртуальных машины и у них 1Gb RAM в каждой, а для нашего проекта 512 может не хватить.

Активация аккаунта Oracle для получения бесплатной виртуальной машины требует международную карту Visa/MasterCard типа WORLD с балансом не менее 100 рублей (списанные средства будут возвращены, это необходимо для верификации карты и владельца). Проверить тип Вашей карты можно заранее на любом сервисе по BIN коду (первые 6 цифр карты), в строке Категория карты должно быть WORLD.

Могу сказать, что эта акция на бесплатные VPS действующая, я зарегистрировал такой аккаунт неделю назад (август 2020).

На этапе выбора образа для виртуалки выберите Ubuntu 20.04 или любой другой дистрибутив linux, если обоснованно считаете это необходимым.

На окончании этого шага Вы должны получить доступ по SSH к новой виртуалке и знать ее внешний (публичный) IP адрес (не пугайтесь, с настройками по умолчанию этот адрес не пингуется из интернета). Для новичков могу сообщить, что приватные (частные) IP адреса начинаются на 10. и выглядят, например, так 10.0.0.15 (есть и другие частные подсети, погуглите) Нам нужен не этот адрес, а другой, общедоступный IP-адрес.

Получаем домен второго уровня бесплатно

Если у Вас уже есть собственный домен и DNS, тогда вы должны создать DNS запись типа А и вписать туда общедоступный IP-адрес VPS. После этого можете переходить к следующему пункту.

Если у Вас еще нет собственного домена, то идем на Freenom.com (кредитная карта не понадобится) подбираем свободный домен и регистрируем его. Большинство доменов, даже 4-х буквенные бесплатны, кроме премиальных (по мнению авторов сервиса). Регистрация аккаунта происходит в момент регистрации домена, также пусть вас не смущает кнопка Оформить заказ — да, для регистрации бесплатного домена нужно оформить заказ. Еще не забудьте указать, что регистрируете домен на 12 месяцев (по умолчанию регистрируют только на 3).

Регистрация бесплатного домена

В момент регистрации домена (на большом мониторе, а не на маленьком как у меня на скриншоте) вы можете сразу указать общедоступный IP адрес вашей виртуалки для нового доменного имени. Указать его нужно два раза (обычно для каждого WEB сервера создается две DNS записи: первая только с именем домена и вторая www.+имя домена). Если у Вас нет поля для ввода IP адреса при регистрации, то ничего страшного, Вы сможете это сделать после регистрации.

После регистрации домена и аккаунта на freenom нужно залогиниться и перейти в меню ServicesMy Domains — напротив Вашего домена нажать Manage Domain, выбрать вкладку Manage Freenom DNS, ввести два раза общедоступный IP-адрес в поле Target и сохранить изменения.

Дальше можете подождать и попить кофе пока обновится кэш DNS.

Успешным результатом этого шага станет возможность подключаться по SSH к Вашей VPS не только по общедоступному IP-адресу, но и по доменному имени.

Первоначальная настройка VPS

  1. Обновим систему
  2. Поставим защиту от китайцев, которых а) много, б) часто сканируют интернет на предмет наличия открытого доступа по паролю SSH на какие-нибудь хосты 
  3. Поставим docker (если что вот альтернативная инструкция)
  4. Дополнительные утилиты по вкусу
  5. У нас используется несколько приложений и в момент запуска контейнеров будет использоваться много оперативной памяти, поэтому создаем файл подкачки по этой инструкции (если у вас не бесплатная виртуалка и памяти больше 2 Gb, то этот пункт можно пропустить и выполнить позднее, если возникнет такая необходимость)
  6. Создаем каталог проекта и скачиваем docker-compose файл с гита
  7. Используя любимый редактор (nano, mc или VSCode с плагином SSH) меняем в файлах конфигурации мой домен iotm.tk на ваш в файле conf/nginx/nginx.conf, в файле conf/telegraf/telegraf.conf в секции [[inputs.mqtt_consumer]] заполняем username и password пользователя mqtt, которого мы пропишем в RabbitMQ позднее, задаем свои пароли по-умолчанию в файле .env, меняем домен на свой и вводим свою почту для уведомлений от LetsEncrypt в файле init-cert.sh, меняем домен iotm.tk в файле docker-compose.yml. Воспользуйтесь поиском в файлах, чтобы не пропустить необходимые исправления.

  8. В панели управления VPS в меню СетиВиртуальные облачные сети — Выбираем Общедоступная подсеть — нажимаем на Default Security List в разделе Списки безопасностиДобавить правила для входящего трафика — и открываем порты 80, 443, 1883, 8883, 18883 для доступа извне к нашему пустому сайту под управлением nginx и MQTT брокеру

    Открываем необходимые порты для доступа в нашу виртуальную облачную сеть

    Все необходимые порты виртуальной облачной сети открыты

  9. Теперь необходимо открыть эти же порты и 22 на хосте в ufw
  10. Генерируем самоподписанные сертификаты для первого запуска nginx запуская скрипт init-cert.sh
  11. Запускаем контейнеры выборочно для получения подписанных сертификатов

    Если все прошло гладко, то Вы получили сертифкаты LetsEncrypt для сайта и эти же сертификаты будут использоваться для RabbitMQ.

  12. Предварительная настройка закончена, запускаем контейнеры скриптом start.sh

Вот в этом месте Вам и придется «поработать напильником». Нужно выставить права на запись каталогу data — именно здесь будут хранится данные каждого контейнера (иначе при каждом перезапуске контейнер не будет «помнить» данные, которые были при предыдущем запуске). Это можно сделать двумя путями:

1.  Выставить права на запись «для всех» на весь каталог data и подкаталоги — но это очень плохое решение с точки зрения безопасности и подойдет только для первого знакомства, чтобы посмотреть в работе все запущенные сервисы. Этот способ подходит только если Вы не будете использовать эти контейнеры и удалите все сразу после ознакомления.

2. Правильный путь — каждому подкаталогу в каталоге data выставить владельцем того пользователя, который запускает сервис в контейнере. Для этого нужно зайти в каждый контейнер и посмотреть пользователя, от которого работает данный сервис и выставить владельцем его на соответствующий подкаталог в data. Чтобы зайти в контейнер и посмотреть пользователей:

Другой способ (предложил Mikhail Voltornist)

Еще вариант:

Мы увидели, что в контейнере grafana пользователь grafana и его UID 472, после этого меняем владельца на каталог data/grafana нашей сборки. Не забудьте выйти из контейнера командой exit (если входили через sh или bash)

Меняем владельца каталога:

Такие операции необходимо проделать для всех контейнеров, где пользователь отличен от root.

Последние штрихи

Итак, смотрим что получилось:

https://example.com/ — это ваш сайт заглушка, можно разместить что-то полезное, положив html файлы в conf/nginx/www

https://example.com/manager/rabbit/ — интерфейс управления RabbitMQ, доступ по умолчанию guest пароль guest — пароль нужно сразу же сменить — помните про китайцев! Создание новых пользователей MQTT на вкладке Admin. Если укажете TAG administrator, то этот пользователь сможет логиниться в WEB интерфейс RabbitMQ и управлять другими пользователями. Если нужно только подключение по MQTT то задавайте TAG None. Создайте нового пользователя, которого прописали в конфиге Telegraf, перезапустите Telegraf. Каждому пользователю после создания нужно дать права на доступ к Virtual host (это внутренний термин RabbitMQ, наш единственный Virtual host это «/»), жмите Set permission.

https://example.com/manager/grafana/ — самое интересное — Grafana. По умолчанию там только один источник данных — Prometheus. Из него берутся данные для мониторинга RabbitMQ и VPS. Нужно создать еще один источник данных InfluxDB — туда Telegraf будет складывать данные из всех топиков, полученные по MQTT. Вообще, в Grafana все интуитивно понятно да и в интернете множество инструкций. Смотрите готовые dashboards, импортируйте чужие и создавайте свои.

https://example.com/manager/portainer/ — WEB интерфейс для управления контейнерами. Тоже нужно задать нормальный пароль после первого входа (admin admin). Можно останавливать/перезапускать контейнеры, смотреть логи каждого контейнера и многое другое — смотрите, изучайте. Именно здесь найдете причину в логах, если что-то не работает.

Как все это еще улучшить?

Улучшать можно бесконечно (в тех пределах, которые позволит оперативка, конечно)

Можете добавить контейнер Alertmanager для генерации алармов по заданным правилам (EMail, Slack и т.п.)

Alertmanager-bot — telegram бот для отправки PUSH уведомлений в Telegram
 
cAdvisor — мониторинг ресурсов занятых каждым контейнером
 
Можно прикрутить на алармы amixr чтобы получать уведомления в виде звонков на телефон и SMS.
 
Добавить в prometheus мониторинг и статистику nginx
 
Добавить в prometheus мониторинг influx
 
Добавить в prometheus мониторинг чего-нибудь еще :)
 
Добавить контейнер Loki для просмотра логов в Grafana
 
Добавить контейнер с сервером OpenVPN, чтобы ходить в интернет через облако Oracle
 
Можно сделать стартовые скрипты создания пользователей, брать пароли из защищенного хранилища…
 
и много чего еще — было бы желание :)
 
 
 
 
Эта статья написана специально для пользователей мобильного приложения IoT Manager (telegraf ожидает сообщения MQTT в JSON формате)
Обсуждение этой статьи у нас на форуме
Обсуждение этой статьи в telegram канале Дмитрия Борисенко 
 
Спасибо, что дочитали до конца.