mikrotik-wiki.ru
Главная
Загрузка...

Telegram-уведомления с MikroTik

RouterOS 7.xАвтоматизация14 мин30 мар. 2026 г.
TelegramVK

Telegram-уведомления с MikroTik — настройка через скрипт

Мониторинг маршрутизатора через Winbox или Grafana удобен, но требует постоянного наблюдения за экраном. Telegram-уведомления решают эту проблему: роутер сам сообщит о проблемах — пропадании интернета, попытках взлома, высокой нагрузке или успешном бэкапе. RouterOS умеет отправлять HTTP-запросы через /tool/fetch, что позволяет взаимодействовать с Telegram Bot API без дополнительного ПО. В этом руководстве создадим Telegram-бота, настроим отправку сообщений и разберём пять практических сценариев: уведомления о падении канала, ежедневные отчёты, оповещения о входе через Winbox, детекция brute-force атак и автоматическая отправка бэкапов.

Описание

Как работает связка MikroTik + Telegram

Архитектура предельно проста:

code
MikroTik ──[HTTPS POST]──> api.telegram.org ──> Telegram Bot ──> Ваш чат/группа

RouterOS использует команду /tool/fetch для отправки HTTP POST-запроса к Telegram Bot API. Telegram принимает запрос и доставляет сообщение в указанный чат. Никакие промежуточные серверы не нужны — роутер общается с Telegram напрямую.

Требования

КомпонентТребование
RouterOS7.20 или новее
ИнтернетРоутер должен иметь доступ к api.telegram.org (HTTPS, порт 443)
DNSДолжен быть настроен DNS на роутере
TelegramУчётная запись Telegram для создания бота
Сертификаты/tool/fetch в RouterOS 7.x поддерживает HTTPS из коробки

Telegram Bot API — ключевые методы

Для уведомлений используется один метод: sendMessage. Формат запроса:

code
POST 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_modeHTML или Markdown (опционально, для форматирования)
  • disable_notificationtrue для тихой отправки без звука

Telegram vs Email: сравнение

ПараметрTelegramEmail
Скорость доставкиМгновенно (< 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. Выполните последовательно:

  1. Отправьте /newbot
  2. Введите имя бота, например: MikroTik Home Router
  3. Введите username бота, например: mikrotik_home_router_bot (должен заканчиваться на bot)
  4. BotFather вернёт токен вида: 7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Сохраните токен — он нужен для всех запросов к API. Токен является секретом — не публикуйте его.

Шаг 2: получение chat_id

Чтобы бот мог отправлять сообщения, нужен числовой ID чата. Способ получения:

  1. Напишите боту любое сообщение (например, /start)
  2. Откройте в браузере: https://api.telegram.org/bot<TOKEN>/getUpdates
  3. В 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>"

Важно: символы <, >, & в данных (не тегах) нужно экранировать как &lt;, &gt;, &amp;.

Проверка

Тестирование базовой отправки

[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"

code
failure: 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"

code
failure: 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. Обходные пути:

  1. Email: используйте /tool/e-mail/send с вложением для отправки бэкапов
  2. Внешний сервер: загружайте бэкап на свой сервер через FTP/SFTP, оттуда отправляйте в Telegram
  3. Текстовый экспорт: отправляйте /export compact как текст сообщения (если помещается в 4096 символов)
  4. Контейнер: запустите на 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
[admin@MikroTik] >
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
Автоматизация / Telegram-уведомления с MikroTik