Telegram-уведомления с MikroTik
Telegram-уведомления с MikroTik — настройка через скрипт
Мониторинг маршрутизатора через Winbox или Grafana удобен, но требует постоянного наблюдения за экраном. Telegram-уведомления решают эту проблему: роутер сам сообщит о проблемах — пропадании интернета, попытках взлома, высокой нагрузке или успешном бэкапе. RouterOS умеет отправлять HTTP-запросы через /tool/fetch, что позволяет взаимодействовать с Telegram Bot API без дополнительного ПО. В этом руководстве создадим Telegram-бота, настроим отправку сообщений и разберём пять практических сценариев: уведомления о падении канала, ежедневные отчёты, оповещения о входе через Winbox, детекция brute-force атак и автоматическая отправка бэкапов.
Описание
Как работает связка MikroTik + Telegram
Архитектура предельно проста:
codeMikroTik ──[HTTPS POST]──> api.telegram.org ──> Telegram Bot ──> Ваш чат/группа
RouterOS использует команду /tool/fetch для отправки HTTP POST-запроса к Telegram Bot API. Telegram принимает запрос и доставляет сообщение в указанный чат. Никакие промежуточные серверы не нужны — роутер общается с Telegram напрямую.
Требования
| Компонент | Требование |
|---|---|
| RouterOS | 7.20 или новее |
| Интернет | Роутер должен иметь доступ к api.telegram.org (HTTPS, порт 443) |
| DNS | Должен быть настроен DNS на роутере |
| Telegram | Учётная запись Telegram для создания бота |
| Сертификаты | /tool/fetch в RouterOS 7.x поддерживает HTTPS из коробки |
Telegram Bot API — ключевые методы
Для уведомлений используется один метод: sendMessage. Формат запроса:
codePOST https://api.telegram.org/bot<TOKEN>/sendMessage Content-Type: application/x-www-form-urlencoded chat_id=<CHAT_ID>&text=<MESSAGE>&parse_mode=HTML
Параметры:
- chat_id — числовой ID чата или группы (не username)
- text — текст сообщения (до 4096 символов)
- parse_mode —
HTMLилиMarkdown(опционально, для форматирования) - disable_notification —
trueдля тихой отправки без звука
Telegram vs Email: сравнение
| Параметр | Telegram | |
|---|---|---|
| Скорость доставки | Мгновенно (< 1 сек) | 1-30 секунд |
| Push-уведомления | Да, на все устройства | Зависит от клиента |
| Настройка в RouterOS | /tool/fetch (1 команда) | /tool/e-mail (SMTP-сервер, порт, логин, TLS) |
| Отправка файлов | Через multipart (ограничено в RouterOS) | Встроенная поддержка вложений |
| Групповые уведомления | Один бот → несколько чатов/групп | Несколько получателей |
| Форматирование | HTML/Markdown, emoji | Полный HTML |
| Размер сообщения | 4096 символов | Практически неограничен |
| Надёжность | Зависит от доступности api.telegram.org | Зависит от SMTP-сервера |
Вывод: Telegram лучше для оперативных уведомлений (алерты, статус), Email — для отправки файлов (бэкапы, логи).
Настройка
Шаг 1: создание Telegram-бота через @BotFather
Откройте Telegram и найдите бота @BotFather. Выполните последовательно:
- Отправьте
/newbot - Введите имя бота, например:
MikroTik Home Router - Введите username бота, например:
mikrotik_home_router_bot(должен заканчиваться наbot) - BotFather вернёт токен вида:
7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Сохраните токен — он нужен для всех запросов к API. Токен является секретом — не публикуйте его.
Шаг 2: получение chat_id
Чтобы бот мог отправлять сообщения, нужен числовой ID чата. Способ получения:
- Напишите боту любое сообщение (например,
/start) - Откройте в браузере:
https://api.telegram.org/bot<TOKEN>/getUpdates - В JSON-ответе найдите поле
"chat":{"id":123456789}— это вашchat_id
Для группы: добавьте бота в группу, отправьте сообщение в группу и проверьте getUpdates. ID группы будет отрицательным числом (например, -1001234567890).
Шаг 3: базовый скрипт отправки в Telegram
Создадим глобальный скрипт, который будем вызывать из других скриптов:
[admin@MikroTik] ># Создаём скрипт-функцию для отправки сообщений в Telegram /system/script/add name="telegram-send" \ policy=read,write,test \ source={ # Параметры бота — замените на свои :local botToken "7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" :local chatId "123456789" # Получаем текст сообщения из глобальной переменной :global telegramMessage # Кодируем спецсимволы для URL :local msg $telegramMessage # Отправляем через Telegram Bot API /tool/fetch \ url="https://api.telegram.org/bot$botToken/sendMessage" \ http-method=post \ http-data="chat_id=$chatId&text=$msg&parse_mode=HTML" \ output=none :log info "Telegram: message sent" # Очищаем переменную :set telegramMessage }
Тестируем отправку:
[admin@MikroTik] ># Устанавливаем сообщение и запускаем скрипт :global telegramMessage "Test from MikroTik" /system/script/run telegram-send
Если всё настроено правильно, в Telegram придёт сообщение "Test from MikroTik".
Шаг 4: улучшенный скрипт с параметрами и обработкой ошибок
Создадим более функциональную версию, которая принимает сообщение как аргумент и обрабатывает ошибки:
[admin@MikroTik] >/system/script/add name="telegram-notify" \ policy=read,write,test \ source={ :local botToken "7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" :local chatId "123456789" # Получаем сообщение из глобальной переменной :global tgMessage :if ([:len $tgMessage] = 0) do={ :log warning "Telegram: empty message, skipping" :return } # Добавляем имя роутера в заголовок :local identity [/system/identity/get name] :local fullMsg "<b>$identity</b>%0A$tgMessage" # Отправляем с обработкой ошибки :do { /tool/fetch \ url="https://api.telegram.org/bot$botToken/sendMessage" \ http-method=post \ http-data="chat_id=$chatId&text=$fullMsg&parse_mode=HTML" \ output=none :log info "Telegram: sent OK" } on-error={ :log error "Telegram: failed to send message" } :set tgMessage }
Теперь в каждом сообщении будет имя роутера (identity), что удобно при мониторинге нескольких устройств.
Пример 1: уведомление о пропадании интернета (Netwatch + скрипт)
Netwatch мониторит доступность хоста и выполняет скрипт при потере связи:
[admin@MikroTik] ># Скрипт при потере связи /system/script/add name="internet-down" \ policy=read,write,test \ source={ :global tgMessage "Internet DOWN - host 8.8.8.8 unreachable" /system/script/run telegram-notify } # Скрипт при восстановлении /system/script/add name="internet-up" \ policy=read,write,test \ source={ :global tgMessage "Internet UP - connectivity restored" /system/script/run telegram-notify } # Netwatch — мониторим Google DNS /tool/netwatch/add \ host=8.8.8.8 \ type=icmp \ interval=30s \ timeout=3s \ up-script="internet-up" \ down-script="internet-down" \ comment="Internet monitor -> Telegram"
Netwatch будет пинговать 8.8.8.8 каждые 30 секунд. При трёх неудачных попытках (timeout × 3) выполнится скрипт internet-down, при восстановлении — internet-up.
Расширенная версия с проверкой двух хостов:
[admin@MikroTik] >/tool/netwatch/add \ host=1.1.1.1 \ type=icmp \ interval=30s \ timeout=3s \ down-script={ # Проверяем второй хост перед тревогой :local secondCheck false :do { /tool/fetch url="https://dns.google" mode=https keep-result=no } on-error={ :set secondCheck true } :if ($secondCheck) do={ :global tgMessage "CRITICAL: Internet fully DOWN (8.8.8.8 and dns.google unreachable)" /system/script/run telegram-notify } } \ comment="Internet double-check monitor"
Пример 2: ежедневный отчёт (CPU, RAM, uptime, клиенты)
Скрипт собирает системную информацию и отправляет сводку:
[admin@MikroTik] >/system/script/add name="daily-report" \ policy=read,write,test \ source={ # Собираем данные :local cpuLoad [/system/resource/get cpu-load] :local freeMemory [/system/resource/get free-memory] :local totalMemory [/system/resource/get total-memory] :local memPercent (($totalMemory - $freeMemory) * 100 / $totalMemory) :local uptime [/system/resource/get uptime] :local version [/system/resource/get version] :local boardName [/system/resource/get board-name] # Считаем подключённых клиентов :local dhcpLeases [/ip/dhcp-server/lease/print count-only where status=bound] # Wi-Fi клиенты (если есть Wi-Fi) :local wifiClients 0 :do { :set wifiClients [/interface/wifi/registration-table/print count-only] } on-error={ :set wifiClients "N/A" } # Активные VPN-подключения :local vpnClients 0 :do { :set vpnClients [/interface/wireguard/peers/print count-only where last-handshake!=""] } on-error={ :set vpnClients 0 } # Трафик на WAN-интерфейсе :local wanRx [/interface/get ether1 rx-byte] :local wanTx [/interface/get ether1 tx-byte] :local wanRxGB ($wanRx / 1073741824) :local wanTxGB ($wanTx / 1073741824) # Формируем сообщение :global tgMessage \ "Daily Report%0A\ ========================%0A\ Model: $boardName%0A\ Version: $version%0A\ Uptime: $uptime%0A\ CPU Load: $cpuLoad %%%0A\ RAM Used: $memPercent %%%0A\ DHCP Leases: $dhcpLeases%0A\ Wi-Fi Clients: $wifiClients%0A\ VPN Peers: $vpnClients%0A\ WAN RX: $wanRxGB GB%0A\ WAN TX: $wanTxGB GB" /system/script/run telegram-notify }
Добавляем в планировщик — отправка каждый день в 09:00:
[admin@MikroTik] >/system/scheduler/add \ name="daily-telegram-report" \ start-date=2025-01-01 \ start-time=09:00:00 \ interval=1d \ on-event="/system/script/run daily-report" \ policy=read,write,test \ comment="Daily system report to Telegram"
Пример 3: уведомление о входе через Winbox
Скрипт парсит системный лог и детектирует входы через Winbox:
[admin@MikroTik] >/system/script/add name="winbox-login-alert" \ policy=read,write,test \ source={ # Ищем записи о входе через Winbox за последнюю минуту :local logEntries [/log/print as-value where topics~"system" message~"logged in"] :foreach entry in=$logEntries do={ :local msg ($entry->"message") :local time ($entry->"time") # Проверяем что это Winbox-вход :if ([:find $msg "winbox"] >= 0) do={ :global tgMessage "Login Alert%0ATime: $time%0A$msg" /system/script/run telegram-notify } } }
Настраиваем запуск через системный лог-триггер. Для этого используем /system/logging/action и /system/logging:
[admin@MikroTik] ># Создаём action, который запускает скрипт /system/logging/action/add \ name="telegram-login" \ target=script \ script="winbox-login-alert" # Логируем события системы через наш action /system/logging/add \ topics=system,info \ action=telegram-login \ prefix="LOGIN"
Альтернативный подход — через планировщик каждые 60 секунд:
[admin@MikroTik] >/system/scheduler/add \ name="check-winbox-logins" \ interval=1m \ on-event="/system/script/run winbox-login-alert" \ policy=read,write,test \ comment="Check for new Winbox logins"
Пример 4: уведомление при brute-force атаке
Связка: firewall детектирует brute-force и добавляет IP в address-list, скрипт отслеживает новые записи и уведомляет:
[admin@MikroTik] ># Firewall-правила для детекции SSH brute-force # (если ещё не настроены — см. статью по защите от brute-force) /ip/firewall/filter/add \ chain=input \ protocol=tcp \ dst-port=22 \ connection-state=new \ action=add-src-to-address-list \ address-list=ssh-bruteforce-stage1 \ address-list-timeout=1m \ comment="SSH brute-force: stage 1" /ip/firewall/filter/add \ chain=input \ protocol=tcp \ dst-port=22 \ connection-state=new \ src-address-list=ssh-bruteforce-stage1 \ action=add-src-to-address-list \ address-list=ssh-bruteforce-stage2 \ address-list-timeout=1m \ comment="SSH brute-force: stage 2" /ip/firewall/filter/add \ chain=input \ protocol=tcp \ dst-port=22 \ connection-state=new \ src-address-list=ssh-bruteforce-stage2 \ action=add-src-to-address-list \ address-list=ssh-bruteforce-blocked \ address-list-timeout=1d \ comment="SSH brute-force: block for 1 day" /ip/firewall/filter/add \ chain=input \ src-address-list=ssh-bruteforce-blocked \ action=drop \ comment="Drop brute-force attackers"
Скрипт мониторинга address-list:
[admin@MikroTik] >/system/script/add name="bruteforce-alert" \ policy=read,write,test \ source={ # Получаем список заблокированных IP :local blockedList [/ip/firewall/address-list/print as-value \ where list="ssh-bruteforce-blocked"] :foreach entry in=$blockedList do={ :local addr ($entry->"address") :local timeout ($entry->"timeout") :local creation ($entry->"creation-time") :local dynamic ($entry->"dynamic") # Уведомляем только о свежих записях (dynamic — созданы firewall) :if ($dynamic = true) do={ # Проверяем что ещё не уведомляли (по комментарию) :local comment ($entry->"comment") :if ([:len $comment] = 0) do={ :local id ($entry->".id") :global tgMessage \ "Brute-force BLOCKED%0A\ IP: $addr%0A\ Time: $creation%0A\ Blocked for: $timeout" /system/script/run telegram-notify # Помечаем что уведомление отправлено /ip/firewall/address-list/set $id comment="notified" } } } } # Запускаем каждые 5 минут /system/scheduler/add \ name="bruteforce-telegram-check" \ interval=5m \ on-event="/system/script/run bruteforce-alert" \ policy=read,write,test \ comment="Check brute-force list and notify"
Пример 5: бэкап конфигурации с отправкой в Telegram
RouterOS может отправить файл бэкапа в Telegram через /tool/fetch, но с ограничениями: метод sendDocument требует multipart/form-data, который /tool/fetch не поддерживает напрямую. Обходной путь — отправить текстовый экспорт как сообщение или использовать /tool/e-mail для отправки файла.
Вариант 1: отправляем уведомление о бэкапе (сам файл сохраняем локально):
[admin@MikroTik] >/system/script/add name="backup-notify" \ policy=read,write,test,sensitive \ source={ :local identity [/system/identity/get name] :local date [/system/clock/get date] :local time [/system/clock/get time] # Создаём бинарный бэкап :local backupName "$identity-$date" /system/backup/save name=$backupName dont-encrypt=yes # Создаём текстовый экспорт /export file="$identity-export-$date" :delay 3s # Проверяем что файлы созданы :local files [/file/print as-value where name~"$identity"] :local fileCount [:len $files] :global tgMessage \ "Backup Complete%0A\ Router: $identity%0A\ Date: $date $time%0A\ Files created: $fileCount%0A\ Backup: $backupName.backup%0A\ Export: $identity-export-$date.rsc" /system/script/run telegram-notify :log info "Backup created and notification sent" } # Еженедельный бэкап — каждое воскресенье в 03:00 /system/scheduler/add \ name="weekly-backup-telegram" \ start-date=2025-01-05 \ start-time=03:00:00 \ interval=7d \ on-event="/system/script/run backup-notify" \ policy=read,write,test,sensitive \ comment="Weekly backup with Telegram notification"
Вариант 2: отправляем текстовый экспорт целиком как сообщение (только для небольших конфигураций):
[admin@MikroTik] >/system/script/add name="backup-export-telegram" \ policy=read,write,test,sensitive \ source={ :local identity [/system/identity/get name] :local date [/system/clock/get date] # Создаём компактный экспорт /export compact file="tg-export" :delay 2s # Читаем файл :local exportContent [/file/get "tg-export.rsc" contents] # Telegram ограничение — 4096 символов :if ([:len $exportContent] > 3800) do={ :global tgMessage "Export too large ($[:len $exportContent] chars) to send via Telegram. Saved locally." /system/script/run telegram-notify } else={ :local botToken "7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" :local chatId "123456789" /tool/fetch \ url="https://api.telegram.org/bot$botToken/sendMessage" \ http-method=post \ http-data="chat_id=$chatId&text=<pre>$exportContent</pre>&parse_mode=HTML" \ output=none } # Удаляем временный файл /file/remove "tg-export.rsc" }
Настройка планировщика для всех скриптов
Сводная таблица расписаний:
[admin@MikroTik] ># Проверяем все задачи планировщика /system/scheduler/print # Добавляем задачи (если ещё не добавлены) # Ежедневный отчёт в 09:00 /system/scheduler/add name="daily-report" \ start-time=09:00:00 interval=1d \ on-event="/system/script/run daily-report" \ policy=read,write,test # Проверка brute-force каждые 5 минут /system/scheduler/add name="bruteforce-check" \ interval=5m \ on-event="/system/script/run bruteforce-alert" \ policy=read,write,test # Бэкап каждое воскресенье в 03:00 /system/scheduler/add name="weekly-backup" \ start-time=03:00:00 interval=7d \ on-event="/system/script/run backup-notify" \ policy=read,write,test,sensitive
Отправка в группу или несколько чатов
Для отправки в группу используйте ID группы (отрицательное число):
[admin@MikroTik] ># Для группы chat_id будет вида -1001234567890 :local chatId "-1001234567890"
Для отправки в несколько чатов создайте массив:
[admin@MikroTik] >/system/script/add name="telegram-multi-send" \ policy=read,write,test \ source={ :local botToken "7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" :local chatIds {123456789; -1001234567890; 987654321} :global tgMessage :if ([:len $tgMessage] = 0) do={ :return } :local identity [/system/identity/get name] :local fullMsg "<b>$identity</b>%0A$tgMessage" :foreach chatId in=$chatIds do={ :do { /tool/fetch \ url="https://api.telegram.org/bot$botToken/sendMessage" \ http-method=post \ http-data="chat_id=$chatId&text=$fullMsg&parse_mode=HTML" \ output=none :delay 1s } on-error={ :log error "Telegram: failed to send to chat $chatId" } } :set tgMessage }
HTML-форматирование сообщений
Telegram Bot API поддерживает HTML-теги в сообщениях:
[admin@MikroTik] ># Доступные HTML-теги: # <b>жирный</b> # <i>курсив</i> # <code>моноширинный</code> # <pre>блок кода</pre> # <a href="URL">ссылка</a> # Пример форматированного сообщения :global tgMessage \ "<b>Router Alert</b>%0A\ Status: <code>WARNING</code>%0A\ CPU: <b>92%</b>%0A\ <i>Check router immediately</i>"
Важно: символы <, >, & в данных (не тегах) нужно экранировать как <, >, &.
Проверка
Тестирование базовой отправки
[admin@MikroTik] ># 1. Проверяем DNS-разрешение /tool/dns-query name=api.telegram.org type=A # 2. Проверяем доступность Telegram API /tool/fetch url="https://api.telegram.org" mode=https keep-result=no # 3. Отправляем тестовое сообщение :global tgMessage "Test message from MikroTik at $[/system/clock/get time]" /system/script/run telegram-notify # 4. Проверяем что сообщение пришло в Telegram
Проверка скриптов
[admin@MikroTik] ># Проверяем список скриптов /system/script/print # Запускаем скрипт вручную и смотрим лог /system/script/run daily-report /log/print where topics~"script" # Проверяем планировщик /system/scheduler/print /system/scheduler/print where name~"telegram" # Смотрим время следующего запуска /system/scheduler/print detail where name="daily-report"
Проверка Netwatch
[admin@MikroTik] ># Проверяем статус Netwatch /tool/netwatch/print # Принудительно тестируем — отключаем WAN /interface/disable ether1 # Ждём 30-90 секунд — должно прийти уведомление # Возвращаем обратно /interface/enable ether1 # Ждём — должно прийти уведомление о восстановлении
Диагностика: чтение ответа Telegram API
Если сообщения не доходят, проверьте ответ API:
[admin@MikroTik] ># Отправляем с выводом ответа в файл /tool/fetch \ url="https://api.telegram.org/bot<TOKEN>/sendMessage" \ http-method=post \ http-data="chat_id=<CHAT_ID>&text=test" \ output=file \ dst-path="telegram-response.txt" # Читаем ответ /file/print where name="telegram-response.txt" # Успешный ответ содержит: {"ok":true,...} # Ошибка: {"ok":false,"error_code":...,"description":"..."}
Мониторинг использования ресурсов скриптами
[admin@MikroTik] ># Проверяем что скрипты не потребляют много ресурсов /system/resource/print # Смотрим историю запусков скриптов /system/script/print detail # Проверяем что scheduler работает корректно /system/scheduler/print detail # Лог ошибок скриптов /log/print where topics~"script" message~"error"
Типичные ошибки
1. Ошибка "DNS name not resolved"
codefailure: dns name not resolved
DNS на роутере не настроен или не работает:
[admin@MikroTik] ># Проверяем DNS-серверы /ip/dns/print # Устанавливаем DNS если не настроен /ip/dns/set servers=8.8.8.8,1.1.1.1 allow-remote-requests=yes # Проверяем разрешение имени /tool/dns-query name=api.telegram.org
2. Ошибка "connection timed out"
codefailure: connection timed out
Роутер не может подключиться к api.telegram.org. Причины:
- Нет интернета на роутере
- Firewall блокирует исходящие соединения на порт 443
- Провайдер блокирует Telegram (актуально для некоторых регионов)
[admin@MikroTik] ># Проверяем маршрут по умолчанию /ip/route/print where dst-address=0.0.0.0/0 # Проверяем доступ к внешним хостам /ping 8.8.8.8 count=3 # Проверяем firewall — нет ли блокировки исходящего HTTPS /ip/firewall/filter/print where chain=output action=drop # Если Telegram заблокирован провайдером — используйте VPN
3. Ошибка "Unauthorized" (401)
code{"ok":false,"error_code":401,"description":"Unauthorized"}
Неверный токен бота. Проверьте:
[admin@MikroTik] ># Убедитесь что токен корректный — без лишних пробелов :local botToken "7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" :put [:len $botToken] # Длина должна быть ~46 символов
4. Ошибка "Bad Request: chat not found" (400)
code{"ok":false,"error_code":400,"description":"Bad Request: chat not found"}
Неверный chat_id или бот не добавлен в группу. Решения:
- Убедитесь, что вы написали боту
/start(для личного чата) - Для группы — добавьте бота в группу и отправьте сообщение
- Проверьте
chat_idчерезgetUpdates
5. Спецсимволы в тексте сообщения
Символы &, #, +, % в тексте могут ломать HTTP-запрос:
[admin@MikroTik] ># Неправильно — символ & разделяет параметры :global tgMessage "CPU 50% & RAM 70%" # Правильно — заменяем спецсимволы :local msg "CPU 50%25 %26 RAM 70%25"
Таблица замены:
| Символ | Замена |
|---|---|
& | %26 |
+ | %2B |
# | %23 |
% | %25 |
| пробел | %20 или + |
| перевод строки | %0A |
6. Лимиты Telegram Bot API
| Лимит | Значение |
|---|---|
| Сообщений в секунду (один чат) | 1 |
| Сообщений в секунду (разные чаты) | 30 |
| Максимальная длина сообщения | 4096 символов |
| Групповые уведомления | 20 сообщений в минуту |
При массовой рассылке добавляйте :delay 1s между отправками, иначе Telegram вернёт ошибку 429 (Too Many Requests).
7. Скрипт работает вручную, но не по расписанию
Проблема чаще всего в политиках (policy):
[admin@MikroTik] ># Проверяем политики скрипта /system/script/print detail where name="telegram-notify" # Проверяем политики планировщика — должны совпадать /system/scheduler/print detail where name="daily-report" # Исправляем — добавляем все нужные политики /system/scheduler/set [find name="daily-report"] \ policy=read,write,test /system/script/set [find name="telegram-notify"] \ policy=read,write,test
Политики скрипта и планировщика должны совпадать. Если скрипт обращается к sensitive-данным (пароли, ключи), нужна политика sensitive.
8. /tool/fetch не поддерживает multipart/form-data
Это основное ограничение: нельзя отправить файл напрямую через Telegram sendDocument. Обходные пути:
- Email: используйте
/tool/e-mail/sendс вложением для отправки бэкапов - Внешний сервер: загружайте бэкап на свой сервер через FTP/SFTP, оттуда отправляйте в Telegram
- Текстовый экспорт: отправляйте
/export compactкак текст сообщения (если помещается в 4096 символов) - Контейнер: запустите на MikroTik контейнер с Python-скриптом, который отправит файл
[admin@MikroTik] ># Вариант с Email — отправка бэкапа как вложения /tool/e-mail/set address=smtp.gmail.com port=587 \ from=mikrotik@example.com \ user=mikrotik@example.com \ password="app-password" \ start-tls=yes /tool/e-mail/send \ to="admin@example.com" \ subject="MikroTik Backup" \ body="Weekly backup attached" \ file="router-backup.backup"
9. Часовой пояс в уведомлениях
Время в сообщениях может быть неправильным, если не настроен часовой пояс:
[admin@MikroTik] ># Проверяем текущее время /system/clock/print # Устанавливаем часовой пояс /system/clock/set time-zone-name=Europe/Moscow # Включаем NTP-клиент /system/ntp/client/set enabled=yes /system/ntp/client/servers/add address=pool.ntp.org
MikroTik ──[HTTPS POST]──> api.telegram.org ──> Telegram Bot ──> Ваш чат/группа
POST https://api.telegram.org/bot<TOKEN>/sendMessage
Content-Type: application/x-www-form-urlencoded
chat_id=<CHAT_ID>&text=<MESSAGE>&parse_mode=HTML
# Создаём скрипт-функцию для отправки сообщений в Telegram
/system/script/add name="telegram-send" \
policy=read,write,test \
source={
# Параметры бота — замените на свои
:local botToken "7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:local chatId "123456789"
# Получаем текст сообщения из глобальной переменной
:global telegramMessage
# Кодируем спецсимволы для URL
:local msg $telegramMessage
# Отправляем через Telegram Bot API
/tool/fetch \
url="https://api.telegram.org/bot$botToken/sendMessage" \
http-method=post \
http-data="chat_id=$chatId&text=$msg&parse_mode=HTML" \
output=none
:log info "Telegram: message sent"
# Очищаем переменную
:set telegramMessage
}
# Устанавливаем сообщение и запускаем скрипт
:global telegramMessage "Test from MikroTik"
/system/script/run telegram-send
/system/script/add name="telegram-notify" \
policy=read,write,test \
source={
:local botToken "7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:local chatId "123456789"
# Получаем сообщение из глобальной переменной
:global tgMessage
:if ([:len $tgMessage] = 0) do={
:log warning "Telegram: empty message, skipping"
:return
}
# Добавляем имя роутера в заголовок
:local identity [/system/identity/get name]
:local fullMsg "<b>$identity</b>%0A$tgMessage"
# Отправляем с обработкой ошибки
:do {
/tool/fetch \
url="https://api.telegram.org/bot$botToken/sendMessage" \
http-method=post \
http-data="chat_id=$chatId&text=$fullMsg&parse_mode=HTML" \
output=none
:log info "Telegram: sent OK"
} on-error={
:log error "Telegram: failed to send message"
}
:set tgMessage
}
# Скрипт при потере связи
/system/script/add name="internet-down" \
policy=read,write,test \
source={
:global tgMessage "Internet DOWN - host 8.8.8.8 unreachable"
/system/script/run telegram-notify
}
# Скрипт при восстановлении
/system/script/add name="internet-up" \
policy=read,write,test \
source={
:global tgMessage "Internet UP - connectivity restored"
/system/script/run telegram-notify
}
# Netwatch — мониторим Google DNS
/tool/netwatch/add \
host=8.8.8.8 \
type=icmp \
interval=30s \
timeout=3s \
up-script="internet-up" \
down-script="internet-down" \
comment="Internet monitor -> Telegram"
/tool/netwatch/add \
host=1.1.1.1 \
type=icmp \
interval=30s \
timeout=3s \
down-script={
# Проверяем второй хост перед тревогой
:local secondCheck false
:do {
/tool/fetch url="https://dns.google" mode=https keep-result=no
} on-error={
:set secondCheck true
}
:if ($secondCheck) do={
:global tgMessage "CRITICAL: Internet fully DOWN (8.8.8.8 and dns.google unreachable)"
/system/script/run telegram-notify
}
} \
comment="Internet double-check monitor"
/system/script/add name="daily-report" \
policy=read,write,test \
source={
# Собираем данные
:local cpuLoad [/system/resource/get cpu-load]
:local freeMemory [/system/resource/get free-memory]
:local totalMemory [/system/resource/get total-memory]
:local memPercent (($totalMemory - $freeMemory) * 100 / $totalMemory)
:local uptime [/system/resource/get uptime]
:local version [/system/resource/get version]
:local boardName [/system/resource/get board-name]
# Считаем подключённых клиентов
:local dhcpLeases [/ip/dhcp-server/lease/print count-only where status=bound]
# Wi-Fi клиенты (если есть Wi-Fi)
:local wifiClients 0
:do {
:set wifiClients [/interface/wifi/registration-table/print count-only]
} on-error={
:set wifiClients "N/A"
}
# Активные VPN-подключения
:local vpnClients 0
:do {
:set vpnClients [/interface/wireguard/peers/print count-only where last-handshake!=""]
} on-error={
:set vpnClients 0
}
# Трафик на WAN-интерфейсе
:local wanRx [/interface/get ether1 rx-byte]
:local wanTx [/interface/get ether1 tx-byte]
:local wanRxGB ($wanRx / 1073741824)
:local wanTxGB ($wanTx / 1073741824)
# Формируем сообщение
:global tgMessage \
"Daily Report%0A\
========================%0A\
Model: $boardName%0A\
Version: $version%0A\
Uptime: $uptime%0A\
CPU Load: $cpuLoad %%%0A\
RAM Used: $memPercent %%%0A\
DHCP Leases: $dhcpLeases%0A\
Wi-Fi Clients: $wifiClients%0A\
VPN Peers: $vpnClients%0A\
WAN RX: $wanRxGB GB%0A\
WAN TX: $wanTxGB GB"
/system/script/run telegram-notify
}
/system/scheduler/add \
name="daily-telegram-report" \
start-date=2025-01-01 \
start-time=09:00:00 \
interval=1d \
on-event="/system/script/run daily-report" \
policy=read,write,test \
comment="Daily system report to Telegram"
/system/script/add name="winbox-login-alert" \
policy=read,write,test \
source={
# Ищем записи о входе через Winbox за последнюю минуту
:local logEntries [/log/print as-value where topics~"system" message~"logged in"]
:foreach entry in=$logEntries do={
:local msg ($entry->"message")
:local time ($entry->"time")
# Проверяем что это Winbox-вход
:if ([:find $msg "winbox"] >= 0) do={
:global tgMessage "Login Alert%0ATime: $time%0A$msg"
/system/script/run telegram-notify
}
}
}
# Создаём action, который запускает скрипт
/system/logging/action/add \
name="telegram-login" \
target=script \
script="winbox-login-alert"
# Логируем события системы через наш action
/system/logging/add \
topics=system,info \
action=telegram-login \
prefix="LOGIN"
/system/scheduler/add \
name="check-winbox-logins" \
interval=1m \
on-event="/system/script/run winbox-login-alert" \
policy=read,write,test \
comment="Check for new Winbox logins"
# Firewall-правила для детекции SSH brute-force
# (если ещё не настроены — см. статью по защите от brute-force)
/ip/firewall/filter/add \
chain=input \
protocol=tcp \
dst-port=22 \
connection-state=new \
action=add-src-to-address-list \
address-list=ssh-bruteforce-stage1 \
address-list-timeout=1m \
comment="SSH brute-force: stage 1"
/ip/firewall/filter/add \
chain=input \
protocol=tcp \
dst-port=22 \
connection-state=new \
src-address-list=ssh-bruteforce-stage1 \
action=add-src-to-address-list \
address-list=ssh-bruteforce-stage2 \
address-list-timeout=1m \
comment="SSH brute-force: stage 2"
/ip/firewall/filter/add \
chain=input \
protocol=tcp \
dst-port=22 \
connection-state=new \
src-address-list=ssh-bruteforce-stage2 \
action=add-src-to-address-list \
address-list=ssh-bruteforce-blocked \
address-list-timeout=1d \
comment="SSH brute-force: block for 1 day"
/ip/firewall/filter/add \
chain=input \
src-address-list=ssh-bruteforce-blocked \
action=drop \
comment="Drop brute-force attackers"
/system/script/add name="bruteforce-alert" \
policy=read,write,test \
source={
# Получаем список заблокированных IP
:local blockedList [/ip/firewall/address-list/print as-value \
where list="ssh-bruteforce-blocked"]
:foreach entry in=$blockedList do={
:local addr ($entry->"address")
:local timeout ($entry->"timeout")
:local creation ($entry->"creation-time")
:local dynamic ($entry->"dynamic")
# Уведомляем только о свежих записях (dynamic — созданы firewall)
:if ($dynamic = true) do={
# Проверяем что ещё не уведомляли (по комментарию)
:local comment ($entry->"comment")
:if ([:len $comment] = 0) do={
:local id ($entry->".id")
:global tgMessage \
"Brute-force BLOCKED%0A\
IP: $addr%0A\
Time: $creation%0A\
Blocked for: $timeout"
/system/script/run telegram-notify
# Помечаем что уведомление отправлено
/ip/firewall/address-list/set $id comment="notified"
}
}
}
}
# Запускаем каждые 5 минут
/system/scheduler/add \
name="bruteforce-telegram-check" \
interval=5m \
on-event="/system/script/run bruteforce-alert" \
policy=read,write,test \
comment="Check brute-force list and notify"
/system/script/add name="backup-notify" \
policy=read,write,test,sensitive \
source={
:local identity [/system/identity/get name]
:local date [/system/clock/get date]
:local time [/system/clock/get time]
# Создаём бинарный бэкап
:local backupName "$identity-$date"
/system/backup/save name=$backupName dont-encrypt=yes
# Создаём текстовый экспорт
/export file="$identity-export-$date"
:delay 3s
# Проверяем что файлы созданы
:local files [/file/print as-value where name~"$identity"]
:local fileCount [:len $files]
:global tgMessage \
"Backup Complete%0A\
Router: $identity%0A\
Date: $date $time%0A\
Files created: $fileCount%0A\
Backup: $backupName.backup%0A\
Export: $identity-export-$date.rsc"
/system/script/run telegram-notify
:log info "Backup created and notification sent"
}
# Еженедельный бэкап — каждое воскресенье в 03:00
/system/scheduler/add \
name="weekly-backup-telegram" \
start-date=2025-01-05 \
start-time=03:00:00 \
interval=7d \
on-event="/system/script/run backup-notify" \
policy=read,write,test,sensitive \
comment="Weekly backup with Telegram notification"
/system/script/add name="backup-export-telegram" \
policy=read,write,test,sensitive \
source={
:local identity [/system/identity/get name]
:local date [/system/clock/get date]
# Создаём компактный экспорт
/export compact file="tg-export"
:delay 2s
# Читаем файл
:local exportContent [/file/get "tg-export.rsc" contents]
# Telegram ограничение — 4096 символов
:if ([:len $exportContent] > 3800) do={
:global tgMessage "Export too large ($[:len $exportContent] chars) to send via Telegram. Saved locally."
/system/script/run telegram-notify
} else={
:local botToken "7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:local chatId "123456789"
/tool/fetch \
url="https://api.telegram.org/bot$botToken/sendMessage" \
http-method=post \
http-data="chat_id=$chatId&text=<pre>$exportContent</pre>&parse_mode=HTML" \
output=none
}
# Удаляем временный файл
/file/remove "tg-export.rsc"
}
# Проверяем все задачи планировщика
/system/scheduler/print
# Добавляем задачи (если ещё не добавлены)
# Ежедневный отчёт в 09:00
/system/scheduler/add name="daily-report" \
start-time=09:00:00 interval=1d \
on-event="/system/script/run daily-report" \
policy=read,write,test
# Проверка brute-force каждые 5 минут
/system/scheduler/add name="bruteforce-check" \
interval=5m \
on-event="/system/script/run bruteforce-alert" \
policy=read,write,test
# Бэкап каждое воскресенье в 03:00
/system/scheduler/add name="weekly-backup" \
start-time=03:00:00 interval=7d \
on-event="/system/script/run backup-notify" \
policy=read,write,test,sensitive
# Для группы chat_id будет вида -1001234567890
:local chatId "-1001234567890"
/system/script/add name="telegram-multi-send" \
policy=read,write,test \
source={
:local botToken "7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:local chatIds {123456789; -1001234567890; 987654321}
:global tgMessage
:if ([:len $tgMessage] = 0) do={ :return }
:local identity [/system/identity/get name]
:local fullMsg "<b>$identity</b>%0A$tgMessage"
:foreach chatId in=$chatIds do={
:do {
/tool/fetch \
url="https://api.telegram.org/bot$botToken/sendMessage" \
http-method=post \
http-data="chat_id=$chatId&text=$fullMsg&parse_mode=HTML" \
output=none
:delay 1s
} on-error={
:log error "Telegram: failed to send to chat $chatId"
}
}
:set tgMessage
}
# Доступные HTML-теги:
# <b>жирный</b>
# <i>курсив</i>
# <code>моноширинный</code>
# <pre>блок кода</pre>
# <a href="URL">ссылка</a>
# Пример форматированного сообщения
:global tgMessage \
"<b>Router Alert</b>%0A\
Status: <code>WARNING</code>%0A\
CPU: <b>92%</b>%0A\
<i>Check router immediately</i>"
# 1. Проверяем DNS-разрешение
/tool/dns-query name=api.telegram.org type=A
# 2. Проверяем доступность Telegram API
/tool/fetch url="https://api.telegram.org" mode=https keep-result=no
# 3. Отправляем тестовое сообщение
:global tgMessage "Test message from MikroTik at $[/system/clock/get time]"
/system/script/run telegram-notify
# 4. Проверяем что сообщение пришло в Telegram
# Проверяем список скриптов
/system/script/print
# Запускаем скрипт вручную и смотрим лог
/system/script/run daily-report
/log/print where topics~"script"
# Проверяем планировщик
/system/scheduler/print
/system/scheduler/print where name~"telegram"
# Смотрим время следующего запуска
/system/scheduler/print detail where name="daily-report"
# Проверяем статус Netwatch
/tool/netwatch/print
# Принудительно тестируем — отключаем WAN
/interface/disable ether1
# Ждём 30-90 секунд — должно прийти уведомление
# Возвращаем обратно
/interface/enable ether1
# Ждём — должно прийти уведомление о восстановлении
# Отправляем с выводом ответа в файл
/tool/fetch \
url="https://api.telegram.org/bot<TOKEN>/sendMessage" \
http-method=post \
http-data="chat_id=<CHAT_ID>&text=test" \
output=file \
dst-path="telegram-response.txt"
# Читаем ответ
/file/print where name="telegram-response.txt"
# Успешный ответ содержит: {"ok":true,...}
# Ошибка: {"ok":false,"error_code":...,"description":"..."}
# Проверяем что скрипты не потребляют много ресурсов
/system/resource/print
# Смотрим историю запусков скриптов
/system/script/print detail
# Проверяем что scheduler работает корректно
/system/scheduler/print detail
# Лог ошибок скриптов
/log/print where topics~"script" message~"error"
failure: dns name not resolved
# Проверяем DNS-серверы
/ip/dns/print
# Устанавливаем DNS если не настроен
/ip/dns/set servers=8.8.8.8,1.1.1.1 allow-remote-requests=yes
# Проверяем разрешение имени
/tool/dns-query name=api.telegram.org
failure: connection timed out
# Проверяем маршрут по умолчанию
/ip/route/print where dst-address=0.0.0.0/0
# Проверяем доступ к внешним хостам
/ping 8.8.8.8 count=3
# Проверяем firewall — нет ли блокировки исходящего HTTPS
/ip/firewall/filter/print where chain=output action=drop
# Если Telegram заблокирован провайдером — используйте VPN
{"ok":false,"error_code":401,"description":"Unauthorized"}
# Убедитесь что токен корректный — без лишних пробелов
:local botToken "7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:put [:len $botToken]
# Длина должна быть ~46 символов
{"ok":false,"error_code":400,"description":"Bad Request: chat not found"}
# Неправильно — символ & разделяет параметры
:global tgMessage "CPU 50% & RAM 70%"
# Правильно — заменяем спецсимволы
:local msg "CPU 50%25 %26 RAM 70%25"
# Проверяем политики скрипта
/system/script/print detail where name="telegram-notify"
# Проверяем политики планировщика — должны совпадать
/system/scheduler/print detail where name="daily-report"
# Исправляем — добавляем все нужные политики
/system/scheduler/set [find name="daily-report"] \
policy=read,write,test
/system/script/set [find name="telegram-notify"] \
policy=read,write,test
# Вариант с Email — отправка бэкапа как вложения
/tool/e-mail/set address=smtp.gmail.com port=587 \
from=mikrotik@example.com \
user=mikrotik@example.com \
password="app-password" \
start-tls=yes
/tool/e-mail/send \
to="admin@example.com" \
subject="MikroTik Backup" \
body="Weekly backup attached" \
file="router-backup.backup"
# Проверяем текущее время
/system/clock/print
# Устанавливаем часовой пояс
/system/clock/set time-zone-name=Europe/Moscow
# Включаем NTP-клиент
/system/ntp/client/set enabled=yes
/system/ntp/client/servers/add address=pool.ntp.org