Как я прикрутил телеграм-бота на Python для мониторинга сервера
С чего я начал
Fail2ban я поставил, n8n подкрутил, но мне хотелось чего-то более гибкого. Конкретно: я хочу написать в Telegram боту «статус» — и получить ответ с загрузкой CPU, RAM, диском и аптаймом. Или написать «бекап» — и запустить резервное копирование баз данных.
n8n такое умеет, но мне надоело тыкать в блоки. Хотелось кода. Чистого, гибкого, без визуального редактора, где линии вечно разъезжаются.
Выбрал aiogram — асинхронную библиотеку для работы с Telegram API на Python. Почему её? Во-первых, она современная, на asyncio. Во-вторых, документация внятная. В-третьих, я уже писал на ней бота для комментариев на сайте — опыт был.
Ставлю aiogram и пишу первого бота
Первым делом — создать виртуальное окружение, чтобы не засорять систему. Я работаю на Ubuntu 24.04, Python 3.12 уже в комплекте:
python3 -m venv tg_monitor
source tg_monitor/bin/activate
pip install aiogram==3.x psutil aiofiles
psutil берёт системные метрики, aiofiles пригодится для логов. Сразу же уткнулся в проблему — aiogram 3.x сильно отличается от второй версии. Там новый API, хендлеры через декораторы, роутеры, и всё завязано на Dispatcher. Пришлось читать документацию с нуля.
Бот получился минимальный: токен берётся из переменной окружения, на команду /start отвечает приветствием, на /status — собирает метрики. Код я закинул в отдельную папку /opt/tg_monitor и завернул в systemd-сервис, чтобы стартовал при загрузке.
Команда /status — глаза сервера
Вот тут я развернулся. Команда шлёт запросы к psutil и возвращает сообщение с:
- CPU — загрузка в процентах по каждому ядру
- RAM — used/total с процентом
- Диск — корневой раздел, /var/log, /backup
- Аптайм — сколько сервер пашет без перезагрузки
- Топ-3 процесса по CPU
Оформил это в красивый Markdown-отчёт. Telegram его отображает — глаз радуется. Первая же отправка показала проблему: бот тупил. Ответ приходил через 5-6 секунд. Почему? psutil на VPS с 4 ядрами делает syscall, который на некоторых виртуализациях тормозит. Пришлось закешировать метрики на 30 секунд.
Обёртка простая:
from functools import lru_cache
import time
@lru_cache(maxsize=1)
def get_metrics(_cache_key):
# собираем всё за один проход
return {"cpu": psutil.cpu_percent(interval=1, percpu=True),
"ram": psutil.virtual_memory()._asdict(),
"disk": psutil.disk_usage('/')._asdict()}
В качестве _cache_key я передаю текущую минуту, округлённую до 30 секунд. Хитро, но работает.
Команда /backup — с риском для данных
Самая опасная функция. Бот запускает bash-скрипт, который дампит все базы MySQL, пакует в архив и кидает в /backup. Когда я первый раз добавил эту команду, я ночь не спал — вдруг кто-то угадает токен и дропнет базы. На всякий случай добавил:
- Ограничение по user_id — команду /backup может выполнить только мой Telegram ID
- Подтверждение через Inline-кнопку: «Точно запустить бекап?»
- Логирование всех вызовов в отдельный файл
aiogram позволяет сделать это элегантно. Фильтры навешиваются прямо на хендлер:
from aiogram.filters import Command
from aiogram.types import Message
@dp.message(Command("backup"), F.from_user.id == MY_ID)
async def backup_cmd(message: Message):
# запускаем через subprocess
pass
Без проверки я однажды чуть не запустил бекап на тестовой VM вместо боевого сервера. Хорошо, что вовремя заметил — просто перепутал окна в терминале.
Что пошло не так
Первая проблема — aiogram 3.x несовместим с aiogram 2.x. Я обновил библиотеку и сломал всех старых ботов. Пришлось переписывать хендлеры под новый синтаксис. Это отняло вечер.
Вторая проблема — утечка памяти. Я повесил на бота фоновую задачу, которая проверяла свободное место на диске каждые 5 минут и асинхронно собирала psutil. Через два дня бот сожрал 500 МБ RAM. Оказалось, asyncio-задача держала ссылку на старые данные. Починил через явное удаление кеша раз в час.
Третья проблема — реконнект. Если Telegram API ложится (а это бывает), aiogram бросает исключение. По дефолту он переподключается, но я не поставил exponential backoff. Бот просто падал и не вставал, пока systemd его не перезапускал.
Деплой и стабильность
Сейчас бот работает уже месяц. Ни одного падения. Я добавил ещё пару команд — /logs (последние 50 строк journalctl) и /uptime (с красивым форматированием). Плюс настроил автоуведомления: если загрузка CPU выше 90% больше минуты — бот сам пишет мне.
Для этого пришлось добавить фоновый воркер внутри aiogram. aiogram поддерживает middleware и фоновые задачи — я запилил цикл с asyncio.sleep(60) и проверкой метрик. Если что-то не так — шлёт сообщение. Удобно.
Кстати, токен храню в .env файле, который читается через python-dotenv. Так безопаснее, чем в коде. Сам .env файл лежит в /opt/tg_monitor с правами 600 и владельцем root.
Итог
Теперь я захожу в Telegram, пишу /status и через секунду вижу, как поживает мой сервер. Могу запустить бекап прямо с телефона, не открывая SSH. Бот стал моей палочкой-выручалочкой — особенно когда я в дороге и надо быстро проверить, всё ли в порядке.
Исходники я выложил в закрытый репозиторий, но если надумаешь повторить — пиши в комменты, скину пример. Aiogram реально стоит освоить, хотя порог входа в третьей версии выше, чем во второй. Но оно того стоит.
Расширю рассказ о создании телеграм-бота для мониторинга сервера дополнительными деталями. С чего я начал. Fail2ban я поставил, n8n подкрутил, но мне хотелось чего-то более гибкого. Конкретно: я хочу написать в Telegram боту «статус» — и получить ответ с загрузкой CPU, RAM, диском и аптаймом. Или написать «бекап» — и запустить резервное копирование баз данных. n8n такое умеет, но мне надоело тыкать в блоки. Хотелось кода. Чистого, гибкого, без визуального редактора, где линии вечно разъезжаются. Автоматизация сервера через бота — это удобство, которое быстро становится привычкой: сервер всегда под рукой, в кармане. Выбрал aiogram — асинхронную библиотеку для работы с Telegram API на Python. Почему её? Во-первых, она современная, на asyncio. Во-вторых, документация внятная. В-третьих, я уже писал на ней бота для комментариев на сайте — опыт был. aiogram — это де-факто стандарт для Telegram-ботов на Python: асинхронный, мощный, с отличной экосистемой.
Ставлю aiogram и пишу первого бота. Первым делом — создать виртуальное окружение, чтобы не засорять систему. Я работаю на Ubuntu 24.04, Python 3.12 уже в комплекте: python3 -m venv tg_monitor, source tg_monitor/bin/activate, pip install aiogram==3.x psutil aiofiles. psutil берёт системные метрики, aiofiles пригодится для логов. Виртуальное окружение — это гигиена Python: каждый проект живёт в своём изолированном окружении, без конфликтов зависимостей. Сразу же уткнулся в проблему — aiogram 3.x сильно отличается от второй версии. Там новый API, хендлеры через декораторы, роутеры, и всё завязано на Dispatcher. Пришлось читать документацию с нуля. Переход с 2.x на 3.x — это переписывание, но новая архитектура чище и мощнее.
Бот получился минимальный: токен берётся из переменной окружения, на команду /start отвечает приветствием, на /status — собирает метрики. Код я закинул в отдельную папку /opt/tg_monitor и завернул в systemd-сервис, чтобы стартовал при загрузке. systemd-сервис — это правильный способ запуска бота на сервере: он стартует при загрузке, перезапускается при падении, пишет логи. Секрет прост: Unit-файл с ExecStart, Restart=always и WorkingDirectory=/opt/tg_monitor. Пять минут на настройку — и бот работает как служба. Хранение токена в переменной окружения — это безопасность: токен не зашит в код и не попадёт в репозиторий.
Команда /status — глаза сервера. Вот тут я развернулся. Команда шлёт запросы к psutil и возвращает сообщение с: CPU — загрузка в процентах по каждому ядру; RAM — used/total с процентом; диск — корневой раздел, /var/log, /backup; аптайм — сколько сервер пашет без перезагрузки; топ-3 процесса по CPU. Оформил это в красивый Markdown-отчёт. Telegram его отображает — глаз радуется. Форматирование в Markdown делает отчёт читабельным: жирные заголовки, моноширинный код, таблицы. Вся ключевая информация о сервере — в одном сообщении. Удобно проверять сервер из любого места, где есть интернет. Это моя главная «панель мониторинга» в кармане.
Первая же отправка показала проблему: бот тупил. Ответ приходил через 5-6 секунд. Почему? psutil на VPS с 4 ядрами делает syscall, который на некоторых виртуализациях тормозит. Пришлось закешировать метрики на 30 секунд. Обёртка простая: from functools import lru_cache, import time, @lru_cache(maxsize=1), def get_metrics(_cache_key): собираем всё за один проход. В качестве _cache_key я передаю текущую минуту, округлённую до 30 секунд. Хитро, но работает. Кеширование метрик — это классическое решение проблемы медленных syscall. Собираем метрики не чаще, чем раз в 30 секунд — и бот отвечает мгновенно. Декоратор lru_cache — элегантный способ кеширования в Python. Плюс замеры с интервалом в 1 секунду дают точные значения. Производительность восстановлена.
Команда /backup — с риском для данных. Самая опасная функция. Бот запускает bash-скрипт, который дампит все базы MySQL, пакует в архив и кидает в /backup. Когда я первый раз добавил эту команду, я ночь не спал — вдруг кто-то угадает токен и дропнет базы. На всякий случай добавил: ограничение по user_id — команду /backup может выполнить только мой Telegram ID; подтверждение через Inline-кнопку: «Точно запустить бекап?»; логирование всех вызовов в отдельный файл. Запуск бекапа с телефона — это удобно, но опасно: если бот попадёт в чужие руки, он сможет манипулировать данными. Поэтому безопасность на первом месте: только мой ID, только с подтверждением, всё логируется.
aiogram позволяет сделать это элегантно. Фильтры навешиваются прямо на хендлер: from aiogram.filters import Command, from aiogram.types import Message, @dp.message(Command(«backup»), F.from_user.id == MY_ID), async def backup_cmd(message: Message): запускаем через subprocess. Фильтры в aiogram — это декларативная проверка условий прямо в декораторе. F.from_user.id == MY_ID отсекает всех, кроме меня. Inline-кнопка добавляет второй этап подтверждения. Без проверки я однажды чуть не запустил бекап на тестовой VM вместо боевого сервера. Хорошо, что вовремя заметил — просто перепутал окна в терминале. Опыт подтвердил: подтверждение нужно всегда. Двойная проверка защищает от случайных и злонамеренных действий.
Что пошло не так. Первая проблема — aiogram 3.x несовместим с aiogram 2.x. Я обновил библиотеку и сломал всех старых ботов. Пришлось переписывать хендлеры под новый синтаксис. Это отняло вечер. Миграция — это боль, но она одноразовая. После переписывания всё стало работать даже лучше: новая архитектура с роутерами чище. Вторая проблема — утечка памяти. Я повесил на бота фоновую задачу, которая проверяла свободное место на диске каждые 5 минут и асинхронно собирала psutil. Через два дня бот сожрал 500 МБ RAM. Оказалось, asyncio-задача держала ссылку на старые данные. Починил через явное удаление кеша раз в час. Утечки памяти в асинхронных задачах — классическая проблема. Ссылки на данные, которые больше не нужны, накапливаются. Решение — периодическая очистка.
Третья проблема — реконнект. Если Telegram API ложится (а это бывает), aiogram бросает исключение. По дефолту он переподключается, но я не поставил exponential backoff. Бот просто падал и не вставал, пока systemd его не перезапускал. Exponential backoff — это стратегия повторных попыток с растущей задержкой: 1 секунда, 2, 4, 8… Она защищает и бота, и API от перегрузки. С backoff бот сам переживает кратковременные сбои Telegram. Без него — падает и ждёт systemd. Эти три проблемы — типичный набор для асинхронных ботов: миграция версий, утечки памяти, реконнекты. Каждая решается, если знать, где копать.
Деплой и стабильность. Сейчас бот работает уже месяц. Ни одного падения. Я добавил ещё пару команд — /logs (последние 50 строк journalctl) и /uptime (с красивым форматированием). Плюс настроил автоуведомления: если загрузка CPU выше 90% больше минуты — бот сам пишет мне. Для этого пришлось добавить фоновый воркер внутри aiogram. aiogram поддерживает middleware и фоновые задачи — я запилил цикл с asyncio.sleep(60) и проверкой метрик. Если что-то не так — шлёт сообщение. Удобно. Команда /logs — это удобный способ посмотреть логи без SSH. Автоуведомления превращают бота из «инструмента по запросу» в проактивного стража: он сам сообщает о проблемах, не дожидаясь вашего вопроса. Фоновый воркер внутри aiogram — элегантное решение.
Кстати, токен храню в .env файле, который читается через python-dotenv. Так безопаснее, чем в коде. Сам .env файл лежит в /opt/tg_monitor с правами 600 и владельцем root. Хранение секретов — это отдельная дисциплина. Токен в коде — это утечка: любой, кто получит код, получит и доступ к боту. .env с правами 600 и владельцем root — только root может его читать. python-dotenv читает переменные окружения из файла — просто и безопасно. Если бот когда-нибудь утечёт в публичный репозиторий — токен останется защищённым. Правила хранения секретов должны соблюдаться с первого дня.
Итог. Теперь я захожу в Telegram, пишу /status и через секунду вижу, как поживает мой сервер. Могу запустить бекап прямо с телефона, не открывая SSH. Бот стал моей палочкой-выручалочкой — особенно когда я в дороге и надо быстро проверить, всё ли в порядке. Возможности растут: /logs для журналов, /uptime для аптайма, автоуведомления о нагрузке. Следующий шаг — интеграция с датчиками температуры и бэкапами. Исходники я выложил в закрытый репозиторий, но если надумаешь повторить — пиши в комменты, скину пример. Aiogram реально стоит освоить, хотя порог входа в третьей версии выше, чем во второй. Но оно того стоит. Бот — это самый удобный способ держать руку на пульсе сервера: он в кармане, он быстрый, он говорит на языке уведомлений. Попробуйте — и вы не захотите возвращаться к SSH каждый раз.