
У меня дома и на работе хватает вещей, которым время от времени нужно что-нибудь сообщить. Мониторинг обнаружил недоступный сервер, Home Assistant заметил открывшуюся дверь, скрипт закончил резервное копирование. Вроде бы ничего сложного: отправить сообщение — и всё.
На практике почти всегда получается очередной бот в Telegram. Отдельный токен, отдельная настройка, иногда ещё и прокси, чтобы он нормально работал из нужной сети. Потом появляется второй сервис, третий, и начинаешь думать: а почему бы им всем не отправлять сообщения в одну свою систему?
Так у меня появился ChimePort — небольшой открытый self-hosted сервер уведомлений с веб-панелью, Android-приложением и Web Push для браузеров. Я уже развернул его у себя и проверил настоящую доставку и на телефон, и в Firefox. Значит, пора рассказать, что получилось.
Зачем мне понадобился ChimePort
Telegram сам по себе тут не виноват. Он неплохо справляется с сообщениями, но для автоматизации у него есть неудобная особенность: уведомления моего сервера оказываются привязаны к чужой инфраструктуре. Сначала нужно завести бота, потом получить токен, разобраться с доставкой, а в некоторых сетях — ещё и с доступом к API.
К тому же разные приложения живут своей жизнью. У мониторинга один бот, у домашней автоматизации другой, у случайного скрипта — третий. А я хочу гораздо более простую схему: есть канал «Серверы», есть канал «Дом», и любая программа, которой разрешено туда писать, отправляет событие по HTTP. Как его показать пользователю — уже задача ChimePort.
При этом я не собирался писать очередной мессенджер. Никаких переписок, групповых чатов и социализации. ChimePort — именно доставка системных и прикладных уведомлений. Источники публикуют события, пользователи их получают.
Как всё устроено
Серверная часть написана на Go, данные хранятся в SQLite. Для установки достаточно одного Docker-контейнера с постоянным томом данных и HTTPS reverse proxy перед ним. Не нужны отдельные PostgreSQL, Redis, брокер сообщений или внешний аккаунт.
Сначала администратор создаёт пользователя, каналы и источники. Источник получает токен с разрешением на конкретные каналы. Такой токен можно передать мониторингу, Home Assistant или собственному скрипту.
Дальше всё выглядит примерно так: программа делает HTTP-запрос в ChimePort, сервер проверяет токен и права, сохраняет сообщение в базу и сообщает о нём клиентам. Если клиент не был подключён, сообщение не пропадает — при следующем обращении он получит его из истории.
Мне важно было разделить хранение сообщения и попытку показать уведомление. Даже если телефон в этот момент без Интернета или браузерный push не дошёл, сам факт события остаётся в своей базе. Это, конечно, не гарантирует, что человек увидел уведомление, но хотя бы позволяет нормально синхронизироваться после сбоя.
Каналы, токены и обычные человеческие настройки
Изначально хотелось просто отправить JSON и увидеть сообщение. Но довольно быстро выяснилось, что даже для одного пользователя нужны некоторые удобства.
- Каналы — чтобы события мониторинга, домашней автоматизации и других систем не смешивались в одну бесконечную ленту.
- Отдельные токены источников — чтобы можно было ограничить доступ и при необходимости отозвать один токен, не ломая остальные интеграции.
- Приоритеты — потому что сообщение о завершённом бэкапе и об отключившемся важном сервере всё-таки не одно и то же.
- Тихие часы, звуки и вибрация в Android-клиенте — чтобы ночью телефон не радовался каждому штатному событию. Срочные сообщения могут обходить тихие часы.
- История и прочтение — возможность открыть приложение позже и посмотреть, что происходило, вместо поисков старых сообщений в чате.
Есть и встроенная страница с примерами отправки: не нужно каждый раз вспоминать, как называется нужный endpoint и какой заголовок передавать.
Android и браузер: два разных клиента
С Android оказалось интереснее, чем хотелось бы. Показать уведомление, пока приложение открыто, довольно просто. Добиться внятной доставки при свёрнутом приложении, с учётом фоновых ограничений системы и энергосбережения, — совсем другая история.
Сейчас Android-клиент умеет работать с несколькими серверами, показывать системные уведомления, разделять прочитанные и непрочитанные события, настраивать каналы и тихие часы. Доставка зависит от устройства и ограничений ОС; обещать, что любой телефон всегда разбудится за долю секунды, было бы неправильно.
Для браузера я сделал PWA и Web Push. ChimePort можно установить как приложение, разрешить уведомления и получать их даже без открытой вкладки, если браузер и операционная система это поддерживают.
Здесь есть любопытный нюанс. Хотя сам ChimePort находится на моём сервере, браузерные фоновые уведомления доставляются через инфраструктуру производителей браузеров — например, Mozilla Push Service для Firefox. Содержимое передаётся в зашифрованном виде, но сам push-шлюз как транспорт никуда не исчезает. Полностью независимая от сторонних посредников система фоновых браузерных push в рамках обычного Web Push не получается.
Установка и обслуживание
ChimePort можно развернуть через Docker Compose или Portainer. В репозитории есть готовая конфигурация, документация по API, создание пользователей, резервные копии, восстановление и обновления. Образы сервера публикуются в GHCR для amd64 и arm64.
Я специально не хотел повторять ситуацию, когда приложение вроде бы работает, пока ничего не случилось, а после переустановки ОС приходится заново собирать его по памяти. Поэтому в комплект вошли проверяемые бэкапы SQLite вместе с ключами, документация по восстановлению и понятные сценарии обновления.
Веб-панель получила три темы — Ocean, Paper и Control. Это не самая важная часть сервиса, но пользоваться собственным инструментом каждый день приятнее, когда на него не больно смотреть.
Что сейчас и что дальше
На момент написания доступен сервер ChimePort v0.1.4, Android-приложение пока имеет статус alpha. Веб-панель, API, история, Android-уведомления и Web Push уже работают. До какого-нибудь большого публичного сервиса с тысячами пользователей тут далеко, да и такой цели пока нет: ChimePort прежде всего делался для собственных задач и тех, кому подходит такой способ доставки.
Из того, чем ещё стоит заняться, — расширить проверку браузерной совместимости, улучшать Android-клиент и интеграции. Но основное уже работает: событие отправляется, сохраняется на сервере и показывается пользователю.
Страница ChimePort на mirv.top — описание возможностей, установки и ссылок.
Исходный код на GitHub — сервер, веб-панель и Android-клиент (AGPL-3.0-only).
Релизы ChimePort — опубликованные версии и готовые сборки.
Инструкция для Portainer — если хочется запустить у себя.
Если попробуете — буду рад замечаниям. Особенно интересен опыт работы браузерных уведомлений на разных системах: у Firefox на Linux уже есть успешно проверенный сценарий, а с остальными устройствами ещё предстоит разобраться.
