Зачем свой сервер уведомлений#
Если у вас есть хотя бы минимальная homelab, вы наверняка сталкивались с ситуацией, когда уведомления сыпятся практически отовсюду - из Proxmox, из PBS бэкапов, из систем безопасности и так далее. Всё это оседает одним общим потоком в вашем мессенджере, в моем случае, в личном Telegram-боте вперемешку с обычными сообщениями. Рано или поздно в этой куче теряется действительно важное, например, что диск не прошёл SMART-тест или что кто-то сканирует ваши порты. Да и просто это начинает восприниматься как информационный шум, на который мозг отказывается реагировать.
Решение - завести отдельное приложение только для того, что происходит в homelab.
Gotify - лёгкий self-hosted сервис именно для этого: простой, быстро разворачивается, гибко настраивается и не тянет за собой лишних зависимостей.
Ко всему прочему у Telegram-бота нет ни приоритетов сообщений, ни отдельных приложений-источников, ни собственного разделения по уровням важности - всё летит в одну ленту. Это еще один повод уйти от этого решения.
Как устроен Gotify#
Схема работы предельно простая и укладывается в одну картинку:
flowchart LR
A1[Proxmox VE] -->|push| G((Gotify server))
A2[CrowdSec] -->|push| G
A3[Любой другой сервис
Linux / Windows] -->|push| G
G --> W[Web UI]
G --> AND[Официальный клиент Android]
G --> IOS[Неофициальный клиент iOS
iGotify]
- Applications - это приложения или сервисы, которые отправляют уведомления на сервер Gotify. Windows/Linux в описании сервиса - это лишь операционные системы, на которых эти приложения-отправители могут работать, сам Gotify-сервер при этом один и работает в Docker-контейнере.
- Gotify server - центральный компонент, который принимает сообщения и раздаёт их подписанным клиентам.
- Clients - то, чем вы читаете уведомления: веб-интерфейс, официальное приложение для Android или неофициальное (но рабочее) приложение iGotify для iOS/iPadOS, которое не указано на официальном сайте, потому что поддерживается энтузиастом, а не командой проекта.
Шаг 1. Установка через Docker Compose#
Gotify можно развернуть бинарником или в Docker - второй вариант удобнее для тех, кто и так держит остальные сервисы в контейнерах.
Официальный docker-compose.yml спрятан на сайте проекта под настройкой docker run в сворачиваемом блоке. Ниже мой реальный рабочий файл - сразу вместе с алертером для Komodo, о котором расскажу в шаге 6, поэтому оба сервиса сидят в одной Docker-сети:
services:
gotify:
image: gotify/server
container_name: gotify
volumes:
- /home/stilicho/docker/gotify:/app/data
#ports:
# - "xxxx:80"
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- gotify
- proxy
environment:
- TZ=${TZ}
- GOTIFY_OIDC_ENABLED=true
- GOTIFY_OIDC_ISSUER=${GOTIFY_OIDC_ISSUER}
- GOTIFY_OIDC_CLIENTID=${GOTIFY_OIDC_CLIENTID}
- GOTIFY_OIDC_CLIENTSECRET=${GOTIFY_OIDC_CLIENTSECRET}
- GOTIFY_OIDC_REDIRECTURL=${GOTIFY_OIDC_REDIRECTURL}
- GOTIFY_OIDC_LINK_BY_USERNAME=true
labels:
- "traefik.enable=true"
- "traefik.http.routers.gotify.entrypoints=web"
- "traefik.http.routers.gotify.rule=Host(`gotify.stilicho.ru`)"
- "traefik.http.middlewares.gotify-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.gotify.middlewares=gotify-https-redirect"
- "traefik.http.routers.gotify-secure.entrypoints=websecure"
- "traefik.http.routers.gotify-secure.rule=Host(`gotify.stilicho.ru`)"
- "traefik.http.routers.gotify-secure.tls=true"
- "traefik.http.routers.gotify-secure.service=gotify"
- "traefik.http.services.gotify.loadbalancer.server.port=80"
- "traefik.docker.network=proxy"
komodo-gotify:
container_name: gotify-alerter
image: foxxmd/komodo-gotify-alerter:latest
environment:
- GOTIFY_URL=${GOTIFY_URL}
- GOTIFY_APP_TOKEN=${GOTIFY_APP_TOKEN}
networks:
- gotify
ports:
- "7000:7000"
depends_on:
- gotify
networks:
gotify:
external: true
proxy:
external: trueВсе переменные вида ${TZ}, ${GOTIFY_OIDC_ISSUER} и так далее compose подставляет из файла .env, который должен лежать рядом с docker-compose.yml:
# Gotify / Authentik OIDC
TZ=Europe/Moscow
GOTIFY_OIDC_ISSUER=https://authentik.stilicho.ru/application/o/gotify/
GOTIFY_OIDC_CLIENTID=клиентский_id_из_Authentik
GOTIFY_OIDC_CLIENTSECRET=клиентский_секрет_из_Authentik
GOTIFY_OIDC_REDIRECTURL=https://gotify.stilicho.ru/auth/oidc/callback
GOTIFY_URL=https://gotify.stilicho.ru
GOTIFY_APP_TOKEN=токен_приложения_komodo_из_GotifyGOTIFY_OIDC_CLIENTSECRET и GOTIFY_APP_TOKEN — полноценные секреты: первый даёт доступ к OIDC-клиенту в Authentik, второй позволяет слать сообщения в Gotify от имени приложения. Не коммитьте .env в git — добавьте его в .gitignore рядом с compose-файлом, а если секрет всё же засветился где-то (например, случайно попал в чат, лог или публичный репозиторий) — обязательно перевыпустите его: в Authentik пересоздайте OIDC client secret, в Gotify — удалите и заново создайте токен приложения.
Разберём, что здесь важно:
volumes- используется bind mount вместо именованного volume: путь на хосте прописан явно, так проще делать бэкапы.ports- закомментирован: прямой доступ по порту отключён, наружу Gotify публикуется только через Traefik (см. блокlabelsниже). Если Traefik не используется, раскомментируйтеportsи уберитеlabels- тогда сервис будет доступен напрямую поhttp://<ip-сервера>:<порт>.security_opt: no-new-privileges:true- если контейнер будет скомпрометирован, злоумышленник не сможет повысить привилегии и выбраться за его пределы.networks: gotifyиproxy- обе сети внешние (external: true), то есть compose их не создаёт сам, а ожидает, что они уже существуют.gotify- отдельная сеть только для Gotify и его алертера,proxy- общая сеть Traefik. Обе нужно создать заранее, если ещё не создавали их под другие сервисы:docker network create gotify docker network create proxyTZ- часовой пояс из.env: Gotify работает с уведомлениями и должен понимать, когда именно что-то произошло.GOTIFY_OIDC_*- включение SSO через внешнего провайдера (в моём случае Authentik), значения тоже из.env. Если у вас нет своего OIDC-провайдера, весь этот блок из четырёх переменных смело удаляйте - Gotify прекрасно работает и с обычной локальной парой логин/пароль.GOTIFY_OIDC_LINK_BY_USERNAME=trueпривязывает уже существующего локального пользователя Gotify к учётке из Authentik по совпадению имени, а не создаёт нового.labels- стандартный набор для публикации через Traefik: HTTP-роутер с редиректом на HTTPS, HTTPS-роутер с TLS и балансировщик на внутренний порт 80 контейнера. Доменgotify.stilicho.ruзамените на свой.komodo-gotify- это уже алертер для Komodo из шага 6; он развёрнут в том же файле и в той же сетиgotify, поэтому в Komodo эндпоинт можно указывать просто по имени контейнера, без IP.GOTIFY_URLиGOTIFY_APP_TOKENтоже берутся из.env.
Поднимаем стек:
docker compose up -dСервис лёгкий и поднимается почти мгновенно - никаких зависимостей вроде отдельной базы данных ему не нужно (по умолчанию используется SQLite).
В переменные окружения можно сразу передать логин и пароль администратора (GOTIFY_DEFAULTUSER_NAME / GOTIFY_DEFAULTUSER_PASS), но удобнее и безопаснее просто зайти под дефолтным admin/admin и сменить пароль сразу через веб-интерфейс - так пароль не осядет в открытом виде в compose-файле.
Шаг 2. Первый вход и смена пароля#
Откройте адрес, на котором развёрнут Gotify - в примере выше это домен через Traefik (https://gotify.stilicho.ru), а если вы раскомментировали ports вместо labels, то http://<ip-сервера>:<порт> - и войдите с логином admin и паролем admin.
Если вы включили GOTIFY_OIDC_* (SSO через Authentik или другой провайдер), на странице входа появится дополнительная кнопка входа через SSO. Локальный admin/admin при этом никуда не пропадет - это отдельный, независимый способ входа.
Сразу после входа:
- Откройте раздел Users.
- Кликните на пользователя
admin. - Задайте новый пароль (или новое имя, если хотите) и сохраните.
Здесь же, при необходимости, можно создать дополнительных пользователей кнопкой Create User - с правами администратора или без, если вы хотите дать доступ кому-то ещё.
Шаг 3. Приложения и клиенты#
В Gotify два независимых понятия, которые легко перепутать:
- Apps - источники, которые отправляют уведомления. У каждого приложения свой токен и свой приоритет по умолчанию (от 0 до 10, где 10 - самое важное).
- Clients - получатели, через которые вы читаете уведомления (веб-браузер, мобильное приложение). У каждого клиента тоже свой токен.
Создайте тестовое приложение:
- Перейдите в Apps → Create Application.
- Укажите имя, например
Test, и при желании короткое описание. - Задайте
Default Priority- на этом этапе можно оставить среднее значение. - Скопируйте появившийся токен приложения - он понадобится любому сервису, который будет слать сообщения через Gotify.
Для мобильного клиента процесс аналогичный, только в разделе Clients:
- Clients → Create, укажите название (например, по имени телефона).
- Скопируйте токен клиента.
- В приложении на телефоне (Android - официальный клиент, iOS/iPadOS - iGotify) укажите URL вашего сервера Gotify и этот токен.
Кнопка «Copy to clipboard» в интерфейсе Gotify не всегда срабатывает стабильно - если токен не скопировался, просто выделите и скопируйте его вручную.
Шаг 4. Уведомления от Proxmox VE#
Начиная с Proxmox VE 8.x, поддержка Gotify встроена «из коробки» - отдельный агент не нужен.
- В интерфейсе Proxmox перейдите в Datacenter → Notifications → Notification Targets.
- Нажмите Add → Gotify.
- Задайте:
- Name - произвольное имя цели, например
homelab; - Server URL - адрес вашего сервера Gotify (
https://gotify.example.com, или просто IP, если сервис не публикуется наружу); - API Token - токен приложения, созданного на предыдущем шаге (удобно сделать отдельное приложение, например
Proxmox, с приоритетом 10).
- Name - произвольное имя цели, например
- Нажмите Add - цель создана.
- Сразу же проверьте связь кнопкой Test: должно прийти тестовое сообщение, которое будет видно в All Messages в интерфейсе Gotify.
Дальше нужно создать Notification Matcher - правило, которое связывает события Proxmox с только что созданной целью:
- Datacenter → Notifications → Notification Matchers → Add.
- Название, например
homelab-matcher, галочка Enable. - В разделе правил нажмите Add, выберите тип
Match Severityи оставьте отмеченными все уровни (info, notice, warning, error, unknown) - так уведомления будут приходить обо всём, что происходит в гипервизоре. - В Target выберите созданную ранее цель (
homelab). - Сохраните.
Проверить работу проще всего на реальном событии - например, запустив ручной бэкап LXC-контейнера или виртуальной машины. В Gotify практически сразу появится сообщение с именем ноды, ID контейнера, статусом и длительностью операции.
Шаг 5. Уведомления от CrowdSec#
Если у вас развёрнут CrowdSec (например, вместе с Traefik), уведомления о попытках сканирования портов или срабатывании бана - это ровно то, что не должно теряться среди прочего шума.
CrowdSec поддерживает Gotify через встроенный http-плагин. Есть один нюанс, из-за которого настройку легко сломать, - имя плагина в двух файлах обязательно должно совпадать.
- Зайдите в директорию, где развёрнут CrowdSec, в подпапку
config. - Откройте
profiles.yamlи раскомментируйте (или добавьте) две строки:notifications:- http_default(название вашего http-плагина - по умолчаниюhttp-default)
- В подпапке
notificationsоткройте (или создайте) файлhttp.yaml. Обратите внимание на строкуname:в начале файла - именно она должна дословно совпадать с тем, что вы указали вprofiles.yaml. - В том же
http.yamlпропишите:url:- адрес вашего сервера Gotify с указанием токена приложения (создайте для CrowdSec отдельное приложение в Gotify с максимальным приоритетом), формат URL и структура запроса указаны в официальной документации CrowdSec для http-плагина Gotify;- при копировании конфига с сайта обязательно проверьте пробелы и отступы YAML - одна лишняя или пропущенная буква, и контейнер запустится, но плагин уведомлений работать не будет.
- Перезапустите стек:
docker compose restartЕсли название плагина в profiles.yaml и в http.yaml не совпадает (например, http-goify в одном файле и http-default в другом), CrowdSec запустится без единой ошибки в логах, но уведомления просто не будут приходить. Если у вас весь трафик проходит через связку Traefik → CrowdSec → Authentik, то от неработающих уведомлений эта цепочка не сломается - но вы просто не узнаете вовремя, что CrowdSec перестал нормально функционировать.
Проверить работу плагина без ложных срабатываний сложно - тестового события «изнутри» нет. Проще всего временно забанить свой же IP вручную через cscli decisions add - уведомление о бане должно прийти в Gotify почти мгновенно.
Шаг 6. Уведомления от Komodo#
Если вы управляете стеками через Komodo (замена Portainer), у неё нет нативной поддержки Gotify - только тип оповещателя Custom, который отправляет вебхук на произвольный HTTP-эндпоинт. Роль «переводчика» между Komodo и Gotify берёт на себя небольшой сторонний сервис - komodo-gotify-alerter от разработчика FoxxMD. Он принимает вебхук от Komodo и пересылает его дальше в Gotify уже в виде обычного push-сообщения.
Сервис komodo-gotify уже описан в общем compose-файле на шаге 1 - он поднимается вместе с самим Gotify, в той же сети gotify, и слушает порт 7000. Напомню, какие переменные у него важны:
GOTIFY_URLиGOTIFY_APP_TOKEN- адрес вашего сервера Gotify и токен приложения; создайте для этого отдельное приложение в Gotify, напримерKomodo.- по желанию можно добавить
GOTIFY_OK_PRIORITY,GOTIFY_WARNING_PRIORITY,GOTIFY_CRITICAL_PRIORITY- привязка приоритета Gotify-уведомления к уровню серьёзности алерта Komodo; - а также
UNRESOLVED_TIMEOUT_TYPESиUNRESOLVED_TIMEOUT- удобная опция для шумных типов алертов вродеServerCpuилиServerMem: если состояние вернулось в норму за указанное время (в миллисекундах), уведомление не отправляется вовсе. В моём файле их нет, но при желании добавляются вenvironmentтем же способом, что и остальные переменные.
Дальше настройка полностью на стороне Komodo:
- В интерфейсе Komodo перейдите в Alerters → Create Alerter.
- Тип - Custom.
- В поле эндпоинта укажите адрес контейнера-алертера и порт 7000. Поскольку Gotify и алертер сидят в одной Docker-сети
gotify, можно указать прямо имя контейнера:http://gotify-alerter:7000(если Komodo запущена в другой сети - соответствующий IP хоста). - При желании ограничьте Alert Types, которые должны попадать в Gotify.
- Сохраните и нажмите Test Alerter - тестовое сообщение должно прийти в Gotify так же, как и все остальные push-уведомления.
Так как в цепочке появляется ещё один HTTP-хоп (Komodo → алертер → Gotify), удобно завести под этот алертер отдельное приложение в Gotify с понятным названием и высоким приоритетом - тогда в общем списке сообщений сразу видно, что уведомление пришло именно от Komodo, а не от самого Docker-хоста.
Что ещё стоит подключить#
Из всего, что умеет слать уведомления в Gotify «из коробки», для домашней инфраструктуры чаще всего критичны три сервиса:
- Proxmox VE - статус бэкапов и события гипервизора (см. выше);
- CrowdSec - попытки сканирования портов и срабатывания банов (см. выше);
- Uptime Kuma - падение любого отслеживаемого сервиса; Gotify поддерживается им нативно, настройка аналогична - свой URL и токен приложения в разделе Notifications.
Всё остальное - уже опционально, но у Gotify достаточно большое community: на GitHub-странице contrib можно найти готовые плагины для Zabbix, MQTT, email-ingest, Slack и десятков других сценариев, либо написать свой на Go.
Telegram и email пока не входят в число сервисов со встроенной поддержкой Gotify - если вам одновременно нужны и они, для них по-прежнему придётся настраивать отдельные интеграции.
Итог#
Gotify закрывает узкую, но очень важную задачу: получать push-уведомления только о том, что происходит на собственной инфраструктуре, не смешивая их с личной перепиской. Развёртывание занимает несколько минут, конфигурация минимальна, а благодаря нативной поддержке в Proxmox VE, CrowdSec и Uptime Kuma можно быстро закрыть три самых критичных источника событий в домашней лаборатории.
Официальная документация проекта: gotify.net/docs Исходный код: github.com/gotify/server





