Скрипты RouterOS — автоматизация задач на MikroTik
RouterOS имеет встроенный скриптовый язык, позволяющий автоматизировать рутинные задачи: резервное копирование, мониторинг каналов, обновление списков блокировки, отправку уведомлений. В этом руководстве разберём синтаксис языка, планировщик задач, полезные готовые скрипты и лучшие практики.
Описание
Возможности скриптового языка RouterOS
Скриптовый язык RouterOS — это не полноценный язык программирования, а специализированный DSL (domain-specific language) для управления маршрутизатором. Он поддерживает:
| Возможность | Описание |
|---|---|
| Переменные | Локальные (:local) и глобальные (:global) |
| Условия | :if ... do= ... else= |
| Циклы | :foreach, :for, :while |
| Массивы | Поддержка массивов и работа с ними |
| Функции | Глобальные переменные-функции |
| Работа с файлами | /file print, /tool fetch |
| HTTP-запросы | /tool/fetch url=... |
/tool/e-mail send | |
| Работа со строками | Конкатенация, поиск подстроки, срезы |
| Регулярные выражения | Оператор ~ для поиска по regex |
| Выполнение CLI-команд | Любая команда RouterOS может быть частью скрипта |
Где размещаются скрипты
Скрипты хранятся в /system/script. Каждый скрипт имеет имя, политику доступа и тело (source). Запустить скрипт можно вручную, по расписанию через /system/scheduler или по событию через /tool/netwatch.
Настройка
Основы синтаксиса
Переменные:
[admin@MikroTik] ># Локальная переменная — видна только в текущем скрипте :local myVar "Hello" :local myNum 42 :local myBool true :local myIP 192.168.1.1 # Глобальная переменная — доступна из любого скрипта :global sharedVar "Shared value" # Массив :local myArray {"item1"; "item2"; "item3"} # Получение значения из команды :local hostname [/system/identity/get name]
Вывод и логирование:
[admin@MikroTik] ># Вывод в терминал :put "Current hostname: $hostname" # Запись в системный лог :log info "Script started" :log warning "Disk space low" :log error "Backup failed"
Условные конструкции:
routeros:local cpuLoad [/system/resource/get cpu-load] :if ($cpuLoad > 80) do={ :log warning "High CPU load: $cpuLoad%" } else={ :log info "CPU load normal: $cpuLoad%" }
Сравнение строк и проверка существования:
routeros:local ifName "ether1" :local ifComment [/interface/get $ifName comment] :if ([:len $ifComment] = 0) do={ :log info "Interface $ifName has no comment" } # Проверка наличия интерфейса :if ([:len [/interface/find name=$ifName]] > 0) do={ :log info "Interface $ifName exists" }
Циклы:
[admin@MikroTik] ># foreach — перебор элементов :local interfaces [/interface/find type=ether] :foreach iface in=$interfaces do={ :local ifName [/interface/get $iface name] :local ifStatus [/interface/get $iface running] :log info "Interface $ifName running=$ifStatus" } # for — цикл со счётчиком :for i from=1 to=5 do={ :log info "Iteration $i" } # while — цикл с условием :local count 0 :while ($count < 10) do={ :set count ($count + 1) }
Работа со строками:
routeros:local str1 "Hello" :local str2 "World" # Конкатенация :local result "$str1 $str2" # Длина строки :local len [:len $str1] # Подстрока (pick) :local sub [:pick $str1 0 3] # Результат: "Hel" # Поиск подстроки (find) :local pos [:find $str1 "ll"] # Результат: 2 # Преобразование типов :local numStr [:tostr 42] :local strNum [:tonum "42"]
Работа с массивами:
[admin@MikroTik] ># Создание массива :local servers {"8.8.8.8"; "1.1.1.1"; "9.9.9.9"} # Добавление элемента :set ($servers->[:len $servers]) "208.67.222.222" # Перебор массива :foreach server in=$servers do={ :local pingResult [/ping $server count=1 as-value] :if ([:len $pingResult] > 0) do={ :log info "Server $server is reachable" } else={ :log warning "Server $server is unreachable" } }
Планировщик задач (Scheduler)
Scheduler позволяет запускать скрипты по расписанию. Каждое задание имеет start-date, start-time и interval.
[admin@MikroTik] ># Запуск скрипта каждый день в 03:00 /system/scheduler add name=daily-backup \ start-time=03:00:00 \ interval=1d \ on-event="/system/script/run backup-to-email" \ policy=read,write,test,policy \ comment="Daily backup at 3 AM" # Запуск каждые 5 минут /system/scheduler add name=health-check \ interval=5m \ on-event="/system/script/run health-monitor" \ policy=read,write,test # Запуск один раз в определённое время /system/scheduler add name=one-time-task \ start-date=2025-01-15 \ start-time=12:00:00 \ on-event=":log info \"One-time task executed\"" \ policy=read
Параметр policy определяет, какие права имеет скрипт при выполнении:
| Policy | Описание |
|---|---|
| read | Чтение конфигурации |
| write | Изменение конфигурации |
| test | Выполнение ping, traceroute, bandwidth-test |
| policy | Управление пользователями и политиками |
| reboot | Перезагрузка маршрутизатора |
| sensitive | Чтение чувствительных данных (пароли, ключи) |
Скрипт 1: Резервное копирование с отправкой на email
Настроим автоматическое ежедневное резервное копирование конфигурации с отправкой на почту.
Шаг 1: Настройка email-клиента:
[admin@MikroTik] >/tool/e-mail set server=smtp.gmail.com \ port=587 \ tls=starttls \ from=mikrotik-backup@company.com \ user=mikrotik-backup@company.com \ password="AppSpecificPassword"
Шаг 2: Создание скрипта:
[admin@MikroTik] >/system/script add name=backup-to-email policy=read,write,test,sensitive source={ :local hostname [/system/identity/get name] :local dateStr [/system/clock/get date] :local timeStr [/system/clock/get time] :local fileName "$hostname-$dateStr" # Создаём binary backup (полная копия, включая пароли) /system/backup/save name=$fileName encryption=aes-sha256 \ password="BackupEncryptionKey2024" # Создаём текстовый export (читаемый, без паролей) /export file=$fileName :delay 5s # Отправляем binary backup /tool/e-mail send \ to="admin@company.com" \ subject="[$hostname] Backup $dateStr $timeStr" \ body="Automated backup from $hostname\nDate: $dateStr $timeStr\nBinary backup (encrypted) attached." \ file="$fileName.backup" :delay 3s # Отправляем текстовый export /tool/e-mail send \ to="admin@company.com" \ subject="[$hostname] Export $dateStr $timeStr" \ body="Automated export from $hostname\nDate: $dateStr $timeStr\nText export attached." \ file="$fileName.rsc" :delay 3s # Удаляем локальные файлы (опционально) /file/remove "$fileName.backup" /file/remove "$fileName.rsc" :log info "Backup sent to email successfully" }
Шаг 3: Создание расписания:
[admin@MikroTik] >/system/scheduler add name=daily-backup \ start-time=03:00:00 interval=1d \ on-event="/system/script/run backup-to-email" \ policy=read,write,test,sensitive \ comment="Daily backup to email"
Скрипт 2: Мониторинг каналов с переключением
Скрипт проверяет доступность основного канала и переключает default route на резервный при отказе.
[admin@MikroTik] >/system/script add name=failover-monitor policy=read,write,test source={ :local mainGateway "203.0.113.1" :local backupGateway "198.51.100.1" :local checkHost "8.8.8.8" :local failCount 0 :local maxFails 3 # Проверяем связь через основной канал :for i from=1 to=$maxFails do={ :local pingResult [/ping $checkHost count=1 interface=ether1-wan \ as-value] :if ([:len $pingResult] = 0) do={ :set failCount ($failCount + 1) } } :if ($failCount >= $maxFails) do={ # Основной канал недоступен — проверяем текущий маршрут :local currentRoute [/ip/route/find where dst-address="0.0.0.0/0" \ gateway=$mainGateway] :if ([:len $currentRoute] > 0) do={ /ip/route/disable $currentRoute :log warning "Main gateway $mainGateway DOWN - switched to backup" # Отправляем уведомление /tool/e-mail send \ to="admin@company.com" \ subject="[ALERT] Main gateway DOWN" \ body="Main gateway $mainGateway is unreachable.\nSwitched to backup: $backupGateway" } } else={ # Основной канал доступен — проверяем, не отключен ли маршрут :local disabledRoute [/ip/route/find where dst-address="0.0.0.0/0" \ gateway=$mainGateway disabled=yes] :if ([:len $disabledRoute] > 0) do={ /ip/route/enable $disabledRoute :log info "Main gateway $mainGateway UP - restored primary route" /tool/e-mail send \ to="admin@company.com" \ subject="[OK] Main gateway restored" \ body="Main gateway $mainGateway is back online." } } }
Запуск каждые 30 секунд:
[admin@MikroTik] >/system/scheduler add name=failover-check \ interval=30s \ on-event="/system/script/run failover-monitor" \ policy=read,write,test
Скрипт 3: Обновление DNS-blacklist через fetch
Скрипт загружает список рекламных доменов и добавляет их в Static DNS с перенаправлением на 0.0.0.0.
[admin@MikroTik] >/system/script add name=dns-blacklist-update policy=read,write,test source={ :local blacklistUrl "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" :local fileName "hosts.txt" :local addedCount 0 :local maxEntries 5000 # Загружаем файл :log info "DNS blacklist: downloading..." /tool/fetch url=$blacklistUrl dst-path=$fileName mode=https :delay 5s # Удаляем старые записи :local oldEntries [/ip/dns/static/find where comment="blacklist"] :foreach entry in=$oldEntries do={ /ip/dns/static/remove $entry } :log info "DNS blacklist: removed old entries" # Читаем файл построчно :local fileContent [/file/get $fileName contents] :local lineStart 0 :local fileLen [:len $fileContent] :while ($lineStart < $fileLen && $addedCount < $maxEntries) do={ :local lineEnd [:find $fileContent "\n" $lineStart] :if ([:typeof $lineEnd] = "nil") do={ :set lineEnd $fileLen } :local line [:pick $fileContent $lineStart $lineEnd] :set lineStart ($lineEnd + 1) # Пропускаем комментарии и пустые строки :if ([:len $line] > 0 && [:pick $line 0 1] != "#") do={ # Формат: "0.0.0.0 domain.com" :local spacePos [:find $line " " 0] :if ([:typeof $spacePos] != "nil") do={ :local domain [:pick $line ($spacePos + 1) [:len $line]] # Убираем возможный \r :if ([:pick $domain ([:len $domain] - 1) [:len $domain]] = "\r") do={ :set domain [:pick $domain 0 ([:len $domain] - 1)] } :if ([:len $domain] > 0 && $domain != "localhost") do={ :do { /ip/dns/static/add name=$domain address=0.0.0.0 \ comment="blacklist" ttl=1d :set addedCount ($addedCount + 1) } on-error={ # Запись уже существует или невалидная — пропускаем } } } } } # Удаляем скачанный файл /file/remove $fileName :log info "DNS blacklist: added $addedCount entries" }
Запуск раз в сутки:
[admin@MikroTik] >/system/scheduler add name=dns-blacklist \ start-time=04:00:00 interval=1d \ on-event="/system/script/run dns-blacklist-update" \ policy=read,write,test \ comment="Update DNS blacklist daily"
Скрипт 4: Netwatch — мониторинг хостов
Netwatch — встроенный инструмент для мониторинга доступности IP-адресов с выполнением скриптов при изменении состояния.
[admin@MikroTik] ># Мониторинг доступности сервера /tool/netwatch add host=10.0.0.100 \ interval=30s \ timeout=2s \ type=icmp \ up-script={ :log info "Server 10.0.0.100 is UP" } \ down-script={ :log error "Server 10.0.0.100 is DOWN" /tool/e-mail send \ to="admin@company.com" \ subject="[ALERT] Server 10.0.0.100 DOWN" \ body="Server 10.0.0.100 is not responding to ICMP." }
Netwatch поддерживает несколько типов проверки:
| Тип | Описание |
|---|---|
| icmp | Стандартный ping |
| tcp-conn | Проверка TCP-подключения к указанному порту |
| http-get | HTTP GET-запрос с проверкой кода ответа |
Пример мониторинга веб-сервера:
[admin@MikroTik] >/tool/netwatch add host=10.0.0.100 \ type=http-get \ http-code-min=200 \ http-code-max=299 \ port=443 \ tls=yes \ interval=1m \ down-script={ :log error "Web server HTTPS check failed" }
Скрипт 5: Автоматическая перезагрузка при утечке памяти
[admin@MikroTik] >/system/script add name=memory-watchdog policy=read,write,reboot source={ :local totalMem [/system/resource/get total-memory] :local freeMem [/system/resource/get free-memory] :local freePercent (($freeMem * 100) / $totalMem) :local hostname [/system/identity/get name] :if ($freePercent < 10) do={ :log warning "Memory critically low: $freePercent% free" /tool/e-mail send \ to="admin@company.com" \ subject="[CRITICAL] $hostname - Low memory, rebooting" \ body="Free memory: $freePercent%\nTotal: $totalMem\nFree: $freeMem\nInitiating reboot..." :delay 10s /system/reboot } else={ :if ($freePercent < 25) do={ :log warning "Memory low: $freePercent% free" } } }
Скрипт 6: HTTP-запросы через /tool/fetch
/tool/fetch позволяет отправлять HTTP/HTTPS запросы — полезно для интеграции с внешними системами.
[admin@MikroTik] ># GET-запрос /tool/fetch url="https://api.example.com/status" mode=https \ dst-path=api-response.txt # POST-запрос (отправка данных) /tool/fetch url="https://hooks.slack.com/services/XXX/YYY/ZZZ" \ mode=https \ http-method=post \ http-header-field="Content-Type: application/json" \ http-data="{\"text\": \"MikroTik alert: link down\"}" \ output=none
Пример интеграции с Telegram:
[admin@MikroTik] >/system/script add name=telegram-notify policy=read,write,test source={ :local botToken "123456789:ABCdefGHI_jklMNOpqrSTUvwxyz" :local chatId "-1001234567890" :local hostname [/system/identity/get name] :global telegramMessage :if ([:len $telegramMessage] = 0) do={ :set telegramMessage "No message specified" } :local url "https://api.telegram.org/bot$botToken/sendMessage" :local postData "chat_id=$chatId&text=$telegramMessage&parse_mode=HTML" :do { /tool/fetch url=$url mode=https http-method=post \ http-data=$postData output=none } on-error={ :log error "Failed to send Telegram notification" } }
Использование:
routeros:global telegramMessage "<b>Alert:</b> Interface ether1 is down" /system/script/run telegram-notify
Проверка
Просмотр всех скриптов
[admin@MikroTik] >/system/script print /system/script print detail where name=backup-to-email
Ручной запуск скрипта
[admin@MikroTik] >/system/script/run backup-to-email
Проверка планировщика
[admin@MikroTik] >/system/scheduler print
Поля next-run и run-count показывают, когда скрипт запустится в следующий раз и сколько раз уже выполнялся.
Просмотр логов скриптов
[admin@MikroTik] >/log print where topics~"script" /log print where message~"backup"
Просмотр Netwatch
[admin@MikroTik] >/tool/netwatch print # Колонка STATUS показывает текущее состояние: up или down
Проверка переменных окружения
[admin@MikroTik] ># Просмотр всех глобальных переменных /system/script/environment print
Типичные ошибки
1. Скрипт не запускается: «insufficient permissions»
Причина: policy скрипта или scheduler не включает нужные права.
Решение:
[admin@MikroTik] ># Проверьте policy скрипта /system/script print detail where name=backup-to-email # Установите нужные rights /system/script set backup-to-email policy=read,write,test,sensitive # Также проверьте policy у scheduler /system/scheduler set daily-backup policy=read,write,test,sensitive
2. Email не отправляется
Причина: неправильная настройка SMTP или блокировка порта.
Решение:
[admin@MikroTik] ># Проверьте настройки email /tool/e-mail print # Тестовая отправка /tool/e-mail send to="admin@company.com" \ subject="Test" body="Test email from MikroTik" # Проверьте логи /log print where topics~"e-mail"
Распространённые проблемы с email:
- Gmail требует App Password (не обычный пароль аккаунта)
- Порт 587 + TLS=starttls для большинства провайдеров
- Порт 465 + TLS=tls для implicit TLS
- DNS должен резолвить SMTP-сервер — проверьте
/ip/dns/print
3. Ошибка парсинга: «expected command name»
Причина: синтаксические ошибки в скрипте. Распространённые причины:
- Пропущены пробелы вокруг операторов:
$a+$bвместо($a + $b) - Не закрыты кавычки или скобки
- Использование
=вместо==в сравнениях (в RouterOS=используется и для присвоения, и для сравнения в зависимости от контекста)
Решение: тестируйте скрипты по частям в терминале перед сохранением.
[admin@MikroTik] ># Проверка синтаксиса — просто вставьте код в терминал # Если ошибка — RouterOS укажет номер строки
4. Переменные теряют значение между вызовами
Причина: использование :local вместо :global. Локальные переменные уничтожаются по завершении скрипта.
Решение: для передачи данных между скриптами используйте :global:
[admin@MikroTik] ># Скрипт 1: устанавливает переменную :global lastBackupTime [/system/clock/get time] # Скрипт 2: читает переменную :global lastBackupTime :log info "Last backup was at $lastBackupTime"
5. /tool/fetch зависает или возвращает ошибку
Причина: DNS не настроен, сертификат не принимается, или файрвол блокирует исходящие подключения.
Решение:
[admin@MikroTik] ># Проверьте DNS /ip/dns/print /ping dns.google count=3 # Для HTTPS — проверьте наличие CA-сертификатов /certificate print # Если CA нет — скачайте /tool/fetch url="https://curl.se/ca/cacert.pem" dst-path=cacert.pem /certificate/import file-name=cacert.pem passphrase=""
6. Scheduler показывает run-count=0
Причина: неверно указан start-time или start-date в будущем.
Решение:
[admin@MikroTik] ># Проверьте системное время /system/clock/print # Удалите start-date для немедленного начала /system/scheduler set daily-backup start-date="" # Или запустите вручную для проверки /system/script/run backup-to-email
Лучшие практики
- Всегда оборачивайте опасные операции в
:do { } on-error={ }— это предотвращает остановку скрипта при ошибке - Используйте
:delayмежду сетевыми операциями — email-отправка и fetch требуют времени - Логируйте начало и конец скрипта — это помогает при диагностике
- Не храните пароли в скриптах открытым текстом — используйте переменные окружения или отдельные зашифрованные файлы
- Ограничивайте policy минимально необходимыми правами — не давайте reboot скрипту мониторинга
- Тестируйте скрипты в терминале перед добавлением в scheduler
- Следите за размером логов — debug-логирование может быстро заполнить память
[admin@MikroTik] ># Очистка старых логов /system/logging/action set memory memory-lines=1000
Скриптовый язык RouterOS — мощный инструмент для автоматизации. Несмотря на своеобразный синтаксис, он позволяет решать большинство задач по мониторингу, резервному копированию и интеграции с внешними системами. Начинайте с простых скриптов и постепенно наращивайте сложность, всегда тестируя изменения в терминале перед добавлением в планировщик.
# Локальная переменная — видна только в текущем скрипте
:local myVar "Hello"
:local myNum 42
:local myBool true
:local myIP 192.168.1.1
# Глобальная переменная — доступна из любого скрипта
:global sharedVar "Shared value"
# Массив
:local myArray {"item1"; "item2"; "item3"}
# Получение значения из команды
:local hostname [/system/identity/get name]
# Вывод в терминал
:put "Current hostname: $hostname"
# Запись в системный лог
:log info "Script started"
:log warning "Disk space low"
:log error "Backup failed"
:local cpuLoad [/system/resource/get cpu-load]
:if ($cpuLoad > 80) do={
:log warning "High CPU load: $cpuLoad%"
} else={
:log info "CPU load normal: $cpuLoad%"
}
:local ifName "ether1"
:local ifComment [/interface/get $ifName comment]
:if ([:len $ifComment] = 0) do={
:log info "Interface $ifName has no comment"
}
# Проверка наличия интерфейса
:if ([:len [/interface/find name=$ifName]] > 0) do={
:log info "Interface $ifName exists"
}
# foreach — перебор элементов
:local interfaces [/interface/find type=ether]
:foreach iface in=$interfaces do={
:local ifName [/interface/get $iface name]
:local ifStatus [/interface/get $iface running]
:log info "Interface $ifName running=$ifStatus"
}
# for — цикл со счётчиком
:for i from=1 to=5 do={
:log info "Iteration $i"
}
# while — цикл с условием
:local count 0
:while ($count < 10) do={
:set count ($count + 1)
}
:local str1 "Hello"
:local str2 "World"
# Конкатенация
:local result "$str1 $str2"
# Длина строки
:local len [:len $str1]
# Подстрока (pick)
:local sub [:pick $str1 0 3]
# Результат: "Hel"
# Поиск подстроки (find)
:local pos [:find $str1 "ll"]
# Результат: 2
# Преобразование типов
:local numStr [:tostr 42]
:local strNum [:tonum "42"]
# Создание массива
:local servers {"8.8.8.8"; "1.1.1.1"; "9.9.9.9"}
# Добавление элемента
:set ($servers->[:len $servers]) "208.67.222.222"
# Перебор массива
:foreach server in=$servers do={
:local pingResult [/ping $server count=1 as-value]
:if ([:len $pingResult] > 0) do={
:log info "Server $server is reachable"
} else={
:log warning "Server $server is unreachable"
}
}
# Запуск скрипта каждый день в 03:00
/system/scheduler add name=daily-backup \
start-time=03:00:00 \
interval=1d \
on-event="/system/script/run backup-to-email" \
policy=read,write,test,policy \
comment="Daily backup at 3 AM"
# Запуск каждые 5 минут
/system/scheduler add name=health-check \
interval=5m \
on-event="/system/script/run health-monitor" \
policy=read,write,test
# Запуск один раз в определённое время
/system/scheduler add name=one-time-task \
start-date=2025-01-15 \
start-time=12:00:00 \
on-event=":log info \"One-time task executed\"" \
policy=read
/tool/e-mail set server=smtp.gmail.com \
port=587 \
tls=starttls \
from=mikrotik-backup@company.com \
user=mikrotik-backup@company.com \
password="AppSpecificPassword"
/system/script add name=backup-to-email policy=read,write,test,sensitive source={
:local hostname [/system/identity/get name]
:local dateStr [/system/clock/get date]
:local timeStr [/system/clock/get time]
:local fileName "$hostname-$dateStr"
# Создаём binary backup (полная копия, включая пароли)
/system/backup/save name=$fileName encryption=aes-sha256 \
password="BackupEncryptionKey2024"
# Создаём текстовый export (читаемый, без паролей)
/export file=$fileName
:delay 5s
# Отправляем binary backup
/tool/e-mail send \
to="admin@company.com" \
subject="[$hostname] Backup $dateStr $timeStr" \
body="Automated backup from $hostname\nDate: $dateStr $timeStr\nBinary backup (encrypted) attached." \
file="$fileName.backup"
:delay 3s
# Отправляем текстовый export
/tool/e-mail send \
to="admin@company.com" \
subject="[$hostname] Export $dateStr $timeStr" \
body="Automated export from $hostname\nDate: $dateStr $timeStr\nText export attached." \
file="$fileName.rsc"
:delay 3s
# Удаляем локальные файлы (опционально)
/file/remove "$fileName.backup"
/file/remove "$fileName.rsc"
:log info "Backup sent to email successfully"
}
/system/scheduler add name=daily-backup \
start-time=03:00:00 interval=1d \
on-event="/system/script/run backup-to-email" \
policy=read,write,test,sensitive \
comment="Daily backup to email"
/system/script add name=failover-monitor policy=read,write,test source={
:local mainGateway "203.0.113.1"
:local backupGateway "198.51.100.1"
:local checkHost "8.8.8.8"
:local failCount 0
:local maxFails 3
# Проверяем связь через основной канал
:for i from=1 to=$maxFails do={
:local pingResult [/ping $checkHost count=1 interface=ether1-wan \
as-value]
:if ([:len $pingResult] = 0) do={
:set failCount ($failCount + 1)
}
}
:if ($failCount >= $maxFails) do={
# Основной канал недоступен — проверяем текущий маршрут
:local currentRoute [/ip/route/find where dst-address="0.0.0.0/0" \
gateway=$mainGateway]
:if ([:len $currentRoute] > 0) do={
/ip/route/disable $currentRoute
:log warning "Main gateway $mainGateway DOWN - switched to backup"
# Отправляем уведомление
/tool/e-mail send \
to="admin@company.com" \
subject="[ALERT] Main gateway DOWN" \
body="Main gateway $mainGateway is unreachable.\nSwitched to backup: $backupGateway"
}
} else={
# Основной канал доступен — проверяем, не отключен ли маршрут
:local disabledRoute [/ip/route/find where dst-address="0.0.0.0/0" \
gateway=$mainGateway disabled=yes]
:if ([:len $disabledRoute] > 0) do={
/ip/route/enable $disabledRoute
:log info "Main gateway $mainGateway UP - restored primary route"
/tool/e-mail send \
to="admin@company.com" \
subject="[OK] Main gateway restored" \
body="Main gateway $mainGateway is back online."
}
}
}
/system/scheduler add name=failover-check \
interval=30s \
on-event="/system/script/run failover-monitor" \
policy=read,write,test
/system/script add name=dns-blacklist-update policy=read,write,test source={
:local blacklistUrl "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"
:local fileName "hosts.txt"
:local addedCount 0
:local maxEntries 5000
# Загружаем файл
:log info "DNS blacklist: downloading..."
/tool/fetch url=$blacklistUrl dst-path=$fileName mode=https
:delay 5s
# Удаляем старые записи
:local oldEntries [/ip/dns/static/find where comment="blacklist"]
:foreach entry in=$oldEntries do={
/ip/dns/static/remove $entry
}
:log info "DNS blacklist: removed old entries"
# Читаем файл построчно
:local fileContent [/file/get $fileName contents]
:local lineStart 0
:local fileLen [:len $fileContent]
:while ($lineStart < $fileLen && $addedCount < $maxEntries) do={
:local lineEnd [:find $fileContent "\n" $lineStart]
:if ([:typeof $lineEnd] = "nil") do={
:set lineEnd $fileLen
}
:local line [:pick $fileContent $lineStart $lineEnd]
:set lineStart ($lineEnd + 1)
# Пропускаем комментарии и пустые строки
:if ([:len $line] > 0 && [:pick $line 0 1] != "#") do={
# Формат: "0.0.0.0 domain.com"
:local spacePos [:find $line " " 0]
:if ([:typeof $spacePos] != "nil") do={
:local domain [:pick $line ($spacePos + 1) [:len $line]]
# Убираем возможный \r
:if ([:pick $domain ([:len $domain] - 1) [:len $domain]] = "\r") do={
:set domain [:pick $domain 0 ([:len $domain] - 1)]
}
:if ([:len $domain] > 0 && $domain != "localhost") do={
:do {
/ip/dns/static/add name=$domain address=0.0.0.0 \
comment="blacklist" ttl=1d
:set addedCount ($addedCount + 1)
} on-error={
# Запись уже существует или невалидная — пропускаем
}
}
}
}
}
# Удаляем скачанный файл
/file/remove $fileName
:log info "DNS blacklist: added $addedCount entries"
}
/system/scheduler add name=dns-blacklist \
start-time=04:00:00 interval=1d \
on-event="/system/script/run dns-blacklist-update" \
policy=read,write,test \
comment="Update DNS blacklist daily"
# Мониторинг доступности сервера
/tool/netwatch add host=10.0.0.100 \
interval=30s \
timeout=2s \
type=icmp \
up-script={
:log info "Server 10.0.0.100 is UP"
} \
down-script={
:log error "Server 10.0.0.100 is DOWN"
/tool/e-mail send \
to="admin@company.com" \
subject="[ALERT] Server 10.0.0.100 DOWN" \
body="Server 10.0.0.100 is not responding to ICMP."
}
/tool/netwatch add host=10.0.0.100 \
type=http-get \
http-code-min=200 \
http-code-max=299 \
port=443 \
tls=yes \
interval=1m \
down-script={
:log error "Web server HTTPS check failed"
}
/system/script add name=memory-watchdog policy=read,write,reboot source={
:local totalMem [/system/resource/get total-memory]
:local freeMem [/system/resource/get free-memory]
:local freePercent (($freeMem * 100) / $totalMem)
:local hostname [/system/identity/get name]
:if ($freePercent < 10) do={
:log warning "Memory critically low: $freePercent% free"
/tool/e-mail send \
to="admin@company.com" \
subject="[CRITICAL] $hostname - Low memory, rebooting" \
body="Free memory: $freePercent%\nTotal: $totalMem\nFree: $freeMem\nInitiating reboot..."
:delay 10s
/system/reboot
} else={
:if ($freePercent < 25) do={
:log warning "Memory low: $freePercent% free"
}
}
}
# GET-запрос
/tool/fetch url="https://api.example.com/status" mode=https \
dst-path=api-response.txt
# POST-запрос (отправка данных)
/tool/fetch url="https://hooks.slack.com/services/XXX/YYY/ZZZ" \
mode=https \
http-method=post \
http-header-field="Content-Type: application/json" \
http-data="{\"text\": \"MikroTik alert: link down\"}" \
output=none
/system/script add name=telegram-notify policy=read,write,test source={
:local botToken "123456789:ABCdefGHI_jklMNOpqrSTUvwxyz"
:local chatId "-1001234567890"
:local hostname [/system/identity/get name]
:global telegramMessage
:if ([:len $telegramMessage] = 0) do={
:set telegramMessage "No message specified"
}
:local url "https://api.telegram.org/bot$botToken/sendMessage"
:local postData "chat_id=$chatId&text=$telegramMessage&parse_mode=HTML"
:do {
/tool/fetch url=$url mode=https http-method=post \
http-data=$postData output=none
} on-error={
:log error "Failed to send Telegram notification"
}
}
:global telegramMessage "<b>Alert:</b> Interface ether1 is down"
/system/script/run telegram-notify
/system/script print
/system/script print detail where name=backup-to-email
/system/script/run backup-to-email
/system/scheduler print
/log print where topics~"script"
/log print where message~"backup"
/tool/netwatch print
# Колонка STATUS показывает текущее состояние: up или down
# Просмотр всех глобальных переменных
/system/script/environment print
# Проверьте policy скрипта
/system/script print detail where name=backup-to-email
# Установите нужные rights
/system/script set backup-to-email policy=read,write,test,sensitive
# Также проверьте policy у scheduler
/system/scheduler set daily-backup policy=read,write,test,sensitive
# Проверьте настройки email
/tool/e-mail print
# Тестовая отправка
/tool/e-mail send to="admin@company.com" \
subject="Test" body="Test email from MikroTik"
# Проверьте логи
/log print where topics~"e-mail"
# Проверка синтаксиса — просто вставьте код в терминал
# Если ошибка — RouterOS укажет номер строки
# Скрипт 1: устанавливает переменную
:global lastBackupTime [/system/clock/get time]
# Скрипт 2: читает переменную
:global lastBackupTime
:log info "Last backup was at $lastBackupTime"
# Проверьте DNS
/ip/dns/print
/ping dns.google count=3
# Для HTTPS — проверьте наличие CA-сертификатов
/certificate print
# Если CA нет — скачайте
/tool/fetch url="https://curl.se/ca/cacert.pem" dst-path=cacert.pem
/certificate/import file-name=cacert.pem passphrase=""
# Проверьте системное время
/system/clock/print
# Удалите start-date для немедленного начала
/system/scheduler set daily-backup start-date=""
# Или запустите вручную для проверки
/system/script/run backup-to-email
# Очистка старых логов
/system/logging/action set memory memory-lines=1000