Диагноз: почему скрипт не работает
Поднял бэкап на MikroTik, добавил в Scheduler — и в 3 ночи получил не файл в Telegram, а тишину. А в логах RouterOS аккуратная запись: expected end of command. Знакомо?
Проблема конкретная. Строка http-content-type="multipart/form-data" — это не параметр команды /tool fetch в RouterOS. Его там нет. Никогда не было. Скрипт, который гуляет по интернету с этой строкой, просто нерабочий.
Дополнительно — там же живет вторая проблема: http-data и upload=yes одновременно не работают. Это два разных режима одной команды. Либо отправляешь данные формы через http-data, либо загружаешь файл через upload=yes. Одновременно — нет.
Что получишь после прочтения этой статьи:
- Рабочий скрипт бэкапа для RouterOS 7.x — проверено на 7.10, 7.13, 7.15
- Точный разбор бага с http-content-type и почему он возникает
- Два варианта скрипта: минимальный и расширенный с обработкой ошибок
- Правильный синтаксис /tool fetch для отправки файлов
- Troubleshooting всех типовых ошибок
Уйдет минут 15. Нужен доступ к MikroTik через WinBox, WebFig или SSH и готовый Telegram-бот с токеном и chat_id.
Системные требования
| Компонент | Минимум | Рекомендуется | Примечание |
|---|---|---|---|
| RouterOS | 7.1 | 7.10+ | На 6.x синтаксис отличается |
| Архитектура | любая | любая | arm, mipsbe, x86, tile — всё работает |
| RAM | 32 MB свободно | 64 MB+ | Для создания файла во время работы |
| Доступ | HTTPS наружу | HTTPS наружу | api.telegram.org порт 443 |
| Telegram | Bot API | Bot API | Бот создается через @BotFather |
На момент публикации актуальна RouterOS 7.15.3. Перед установкой проверь свежие релизы на mikrotik.com/download.
Архитектура: как работает отправка файла
Причины ошибки expected end of command
Разберем конкретно, что идет не так в скриптах которые гуляют по интернету. Не для красоты — чтобы ты понял, что исправлено и почему.
Причина 1: http-content-type не существует как параметр /tool fetch
Команда /tool fetch в RouterOS имеет фиксированный набор параметров. http-content-type — не один из них. RouterOS встречает незнакомый параметр и выдает expected end of command. Точка.
Откуда взялась эта строка в интернете — история темная. Скорее всего кто-то перепутал с curl или скопировал из старой версии документации. Потом статья разошлась копипастой. Сейчас она живет в десятках «рабочих» гайдов.
Когда RouterOS отправляет файл через upload=yes, content-type выставляется автоматически. Указывать его вручную не нужно — нет смысла и нет возможности.
Причина 2: http-data и upload=yes конфликтуют
Это два разных режима работы fetch:
http-data— POST-запрос с телом в виде строки. Для отправки текстовых параметровupload=yes+src-path— загрузка файла. Для отправки бинарных данных
При отправке файла в Telegram нужен второй вариант. Параметры вроде chat_id и caption передаются в URL как query-string, а не через http-data.
Причина 3: перенос строки через backslash в multiline-командах
Синтаксис \ для переноса строки работает в RouterOS, но RouterOS версий ниже 7.7 иногда его некорректно обрабатывает внутри :do блоков и при вызове из Scheduler. Если скрипт запускается вручную — работает. Из расписания — нет. Поэтому команду fetch лучше писать в одну строку или через переменную URL.
Подготовка: создаем Telegram-бота
Если бот уже есть — пропусти этот раздел. Если нет — займет 3 минуты.
Создаем бота через @BotFather
Открой Telegram, найди @BotFather и выполни:
- Отправь
/newbot - Введи имя бота — например
MikroTik Backup - Введи username — должен заканчиваться на
bot, напримерmikrotik_my_backup_bot - Получи токен вида:
1234567890:ABCdefGHIjklMNOpqrsTUVwxyz
Сохрани токен. Он понадобится в скрипте.
Получаем Chat ID
Отправь боту любое сообщение — хотя бы /start. Потом открой в браузере:
https://api.telegram.org/botВАШ_ТОКЕН/getUpdates
В ответе найди "chat":{"id":123456789} — это твой Chat ID. Запиши его.
Для приватного канала: создай канал, добавь бота как администратора, отправь в канал любое сообщение, снова посмотри getUpdates. Chat ID канала начинается с -100, например -1001234567890.
Проверяем доступ к Telegram API с роутера
Зайди в терминал MikroTik и выполни:
/tool/fetch url="https://api.telegram.org" keep-result=no
Если ошибок нет — роутер достает Telegram. Если ошибка SSL — смотри раздел Troubleshooting про сертификаты.
Рабочий скрипт резервного копирования MikroTik для RouterOS 7
Вариант 1: минимальный — только .backup файл
Подходит если нужно просто отправлять бэкап и не городить огород.
# === Настройки ===
:local botToken "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz"
:local chatID "987654321"
# === Формируем имя файла ===
:local deviceName [/system identity get name]
:local date [/system clock get date]
:local time [/system clock get time]
:local timeClean ([:pick $time 0 2] . [:pick $time 3 5] . [:pick $time 6 8])
:local backupFile ("$deviceName-$date-$timeClean.backup")
# === Создаем бэкап ===
/system/backup/save name=$backupFile
:delay 2s
# === Отправляем в Telegram ===
:local tgUrl ("https://api.telegram.org/bot$botToken/sendDocument?chat_id=$chatID&caption=Backup+$deviceName+$date")
/tool/fetch url=$tgUrl http-method=post mode=https upload=yes src-path=$backupFile keep-result=no
# === Логируем и чистим ===
:log info ("Telegram backup sent: $backupFile")
:delay 3s
/file/remove $backupFile
Вариант 2: расширенный — .backup + .rsc экспорт + уведомления об ошибках
Это версия для тех кто хочет и бинарный бэкап, и текстовый экспорт конфигурации, и уведомление в Telegram если что-то пошло не так.
Бинарный .backup можно восстановить только на той же модели и версии RouterOS. Текстовый .rsc — переносится на любое устройство командой /import. Поэтому иметь оба полезно.
# ============================================
# MikroTik RouterOS 7 - Backup to Telegram
# Версия: 3.0 - исправленный рабочий скрипт
# IT-Apteka.com
# ============================================
# === НАСТРОЙКИ - замени на свои ===
:local botToken "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz"
:local chatID "987654321"
# Пароль для шифрования бэкапа. Оставь пустым если не нужен.
:local backupPassword ""
# === Формируем данные ===
:local deviceName [/system identity get name]
:local rosVersion [/system/resource/get version]
:local date [/system/clock/get date]
:local time [/system/clock/get time]
:local timeClean ([:pick $time 0 2] . [:pick $time 3 5] . [:pick $time 6 8])
:local backupFile ("$deviceName-$date-$timeClean.backup")
:local exportFile ("$deviceName-$date-$timeClean.rsc")
# === Создаем файлы ===
:if ([:len $backupPassword] > 0) do={
/system/backup/save name=$backupFile password=$backupPassword
} else={
/system/backup/save name=$backupFile
}
:delay 2s
/export file=$exportFile
:delay 2s
# === Отправка файла - единственный правильный способ ===
# chat_id и caption идут в URL, не в http-data
# upload=yes + src-path - режим загрузки файла
# http-content-type НЕ указываем - RouterOS выставляет сам
:local result1 true
:local result2 true
:local urlBackup ("https://api.telegram.org/bot$botToken/sendDocument?chat_id=$chatID&caption=Backup:+$deviceName+ROS+$rosVersion+$date+$time")
:do {
/tool/fetch url=$urlBackup http-method=post mode=https upload=yes src-path=$backupFile keep-result=no timeout=60s
} on-error={
:set result1 false
:log error ("Telegram backup: failed to send .backup file")
}
:delay 3s
:local urlExport ("https://api.telegram.org/bot$botToken/sendDocument?chat_id=$chatID&caption=Export:+$deviceName+$date+$time")
:do {
/tool/fetch url=$urlExport http-method=post mode=https upload=yes src-path=$exportFile keep-result=no timeout=60s
} on-error={
:set result2 false
:log error ("Telegram backup: failed to send .rsc file")
}
# === Итоговое уведомление ===
:local statusMsg ""
:if ($result1 = true && $result2 = true) do={
:set statusMsg ("OK: backup+export sent from $deviceName at $date $time")
:log info $statusMsg
} else={
:set statusMsg ("ERROR: backup failed on $deviceName at $date $time. Check logs.")
:log error $statusMsg
}
:local urlMsg ("https://api.telegram.org/bot$botToken/sendMessage?chat_id=$chatID&text=$statusMsg")
:do {
/tool/fetch url=$urlMsg http-method=post mode=https keep-result=no
} on-error={
:log error ("Telegram backup: failed to send status message")
}
# === Чистим файлы с роутера ===
:delay 5s
:do { /file/remove $backupFile } on-error={}
:do { /file/remove $exportFile } on-error={}
:log info ("Telegram backup script finished")
Сохраняем скрипт в RouterOS
Через WinBox: System -> Scripts -> Add New.
- Name:
telegram-backup - Policy: read, write, policy, test — все четыре нужны
- Source: вставь скрипт выше
Через терминал:
/system/script/add name="telegram-backup" policy=read,write,policy,test source="ВАШ_СКРИПТ_ЗДЕСЬ"
Тестируем вручную
/system/script/run telegram-backup
Через 10-15 секунд в Telegram должны прийти два файла и статусное сообщение. Если не пришли — смотри логи:
/log/print where topics~"script"
Автоматизация через Scheduler
Настраиваем запуск каждую ночь в 3:00. В это время нагрузка минимальная, канал свободен.
/system/scheduler/add \
name="telegram-backup-daily" \
on-event="/system/script/run telegram-backup" \
start-time=03:00:00 \
interval=1d \
comment="Daily backup to Telegram"
Проверяем что задача создана и активна:
/system/scheduler/print
В выводе должна быть твоя задача со статусом и временем следующего запуска. Поле next-run покажет когда запустится.
Проверка работы
# Проверяем доступность Telegram API
/ping api.telegram.org count=3
# Смотрим логи скрипта
/log/print where topics~"script"
# Смотрим все задачи планировщика
/system/scheduler/print
# Проверяем файлы на роутере (должны создаваться и удаляться)
/file/print
# Тест: запускаем принудительно
/system/script/run telegram-backup
Таблица портов
| Назначение | Протокол | Порт | Направление | Хост |
|---|---|---|---|---|
| Telegram Bot API | TCP/HTTPS | 443 | Исходящий | api.telegram.org |
| DNS-резолвинг | UDP | 53 | Исходящий | DNS-сервер |
Никаких входящих портов открывать не нужно. MikroTik сам инициирует соединение наружу.
Troubleshooting: разбор ошибок
Ошибка: expected end of command
Решение: убери строку http-content-type="multipart/form-data" \ полностью. Используй скрипт из этой статьи.
Ошибка: SSL: certificate verify failed
# Скачиваем актуальный корневой сертификат
/tool/fetch url="https://curl.se/ca/cacert.pem" dst-path=cacert.pem
# Импортируем
/certificate/import file-name=cacert.pem passphrase=""
# Проверяем
/certificate/print count-only
# Повторяем тест
/tool/fetch url="https://api.telegram.org" keep-result=no
Ошибка: timeout при отправке
Бэкап большой или канал медленный. В команде fetch добавь timeout=120s. Если файл больше 50 MB — это уже не бэкап конфига, это что-то лишнее. Проверь что лежит в /file.
Ошибка: file not found
В скрипте уже стоит :delay 2s после создания бэкапа. Если ошибка продолжается — увеличь до :delay 5s. На медленных CHR-инстансах файл иногда пишется дольше.
Ошибка: script не запускается из Scheduler, но работает вручную
Классика. Три причины:
- В поле
on-eventпрописан неверный путь к скрипту - У скрипта не хватает прав policy
- Scheduler отключен или стоит неверная дата start-date
# Проверяем настройки задачи
/system/scheduler/print detail
# Проверяем права скрипта
/system/script/print detail
# Принудительно запускаем из Scheduler (симулируем)
/system/scheduler/print
Поле on-event должно содержать именно /system/script/run telegram-backup. Проверь без опечаток.
Ошибка: chat not found или 400 Bad Request
Неверный chat_id или бот не добавлен в канал. Проверь:
- Chat ID скопирован точно, включая знак минус для каналов
- Боту отправлено хотя бы одно сообщение перед getUpdates
- Бот добавлен в канал с правами администратора
# Тест отправки сообщения прямо с роутера
:local testUrl "https://api.telegram.org/botТВОЙ_ТОКЕН/sendMessage?chat_id=ТВОЙ_CHAT_ID&text=test"
/tool/fetch url=$testUrl http-method=post mode=https keep-result=no
Если в Telegram пришло слово «test» — бот и chat_id рабочие. Если нет — проблема в них, не в скрипте отправки файла.
Скрипт работает, но файлы не удаляются
Команда удаления выполняется до того как fetch завершил отправку. Увеличь задержку перед удалением до 10-15 секунд. В расширенном скрипте уже стоит :delay 5s, но на медленных каналах этого мало.
Безопасность
Что нужно сделать для нормальной безопасности:
- Шифруй .backup файл паролем:
/system/backup/save name=$f password="сильный_пароль" - Создай приватный Telegram-канал, не используй личный чат
- Включи двухфакторную аутентификацию в Telegram
- Ограничь доступ к роутеру по IP через firewall input chain
- Отдельный пользователь RouterOS только для скрипта — не под admin
# Создаем пользователя только для скриптов бэкапа
/user/add name=backup-script password="сильный_пароль" group=read
# Ограничиваем доступ к веб-интерфейсу по IP
/ip/service/set www allowed-address=192.168.1.0/24
/ip/service/set www-ssl allowed-address=192.168.1.0/24
Резервное копирование: что, как часто, где хранить
| Тип файла | Содержимое | Размер | Частота | Где хранить |
|---|---|---|---|---|
| .backup | Полная конфигурация + ключи | 100-500 KB | Ежедневно | Telegram + локально |
| .rsc | Конфигурация в текстовом виде | 20-100 KB | Ежедневно | Telegram + git |
Telegram хранит файлы неограниченно. Но дополнительно рекомендую раз в неделю выгружать критичные бэкапы куда-то ещё — хотя бы на домашний NAS или в облачное хранилище.
Как восстановить бэкап
Скачай файл из Telegram. Залей на роутер через WinBox (Files) или SCP. Потом:
# Восстановление из бинарного бэкапа
/system/backup/load name=router-backup.backup
# Восстановление из текстового экспорта
/import file=router-config.rsc
Обновление RouterOS без потери скрипта
# Перед обновлением: экспортируй скрипты
/system/script/print detail
# После обновления: проверь что скрипты на месте
/system/script/print
# Проверь Scheduler
/system/scheduler/print
# Запусти тест вручную
/system/script/run telegram-backup
После мажорного обновления RouterOS (например с 7.13 на 7.15) обязательно тестируй скрипт вручную — иногда меняется поведение /tool fetch. Редко, но бывает.
Альтернативные решения
Telegram — не единственный вариант. Вот короткое сравнение если нужно что-то другое:
| Метод | Сложность | Стоимость | Надежность | Подходит когда |
|---|---|---|---|---|
| Telegram Bot API | Низкая | Бесплатно | Высокая | Всегда — самый простой вариант |
| FTP/SFTP | Средняя | Сервер | Высокая | Есть свой сервер, нужна структура |
| Email SMTP | Средняя | Бесплатно | Низкая | Нет альтернатив — Gmail часто блокирует |
| SMB сетевая папка | Низкая | Бесплатно | Средняя | Только в локальной сети |
| MikroTik Cloud | Минимальная | Бесплатно | Высокая | Нужен только бэкап, без уведомлений |
Про MikroTik Cloud стоит сказать отдельно. Это встроенный функционал RouterOS — /system/cloud. Делает бэкап конфигурации в облако MikroTik без скриптов. Ограничение: только один бэкап, нет истории версий, нет уведомлений. Как дополнение к Telegram — нормально.
FAQ
Почему http-content-type вызывает ошибку expected end of command?
Потому что такого параметра у команды /tool fetch нет. RouterOS встречает неизвестный аргумент и останавливает выполнение. Это не баг RouterOS — это ошибка в скрипте. Убери эту строку и используй upload=yes с src-path.
Как проверить что скрипт вообще запускается из Scheduler?
# Смотрим когда задача запускалась последний раз
/system/scheduler/print detail
# Смотрим логи за последние сутки
/log/print where topics~"script" and time>=00:00:00
В RouterOS 7.10+ в выводе scheduler print detail есть поле run-count — сколько раз задача запускалась. Если 0 — никогда не запускалась.
Что если Telegram недоступен из роутера?
Проверь файрвол — в цепочке output не должно быть блокировки на порт 443. Проверь DNS — роутер должен резолвить api.telegram.org. Если провайдер блокирует Telegram — нужен прокси или VPN на уровне роутера.
# Диагностика
/ping api.telegram.org count=3
/ip/dns/cache/print
/ip/firewall/filter/print where chain=output
Можно ли отправлять бэкапы с нескольких роутеров в один канал?
Да. Один бот, один канал, разные роутеры — всё работает. В имени файла и caption будет имя каждого устройства из [/system identity get name]. Задай разным роутерам разные имена через /system/identity/set name="router-office".
Почему .backup файл нельзя восстановить на другой модели?
Бинарный .backup содержит аппаратно-специфичные настройки: имена интерфейсов, номера слотов, конкретные чипы. На другой модели они будут другими. Для переноса конфигурации используй .rsc — текстовый экспорт. Его можно импортировать на любой MikroTik, хотя придется подправить имена интерфейсов вручную.
Как зашифровать .backup файл?
# При создании бэкапа добавь пароль
/system/backup/save name=router.backup password="сильный_пароль_тут"
# При восстановлении RouterOS спросит пароль
/system/backup/load name=router.backup
Пароль нигде не хранится — только в твоей голове и менеджере паролей. Потеряешь — файл не откроешь.
Итог
Скрипт был нерабочим из-за одной строки: http-content-type="multipart/form-data". Такого параметра в RouterOS нет. Убери её — и скрипт заработает. Плюс перенеси chat_id в URL вместо http-data при использовании upload=yes.
Теперь у тебя рабочая схема: ночью Scheduler запускает скрипт, скрипт создает .backup и .rsc, отправляет оба файла в Telegram, пишет статус, чистит временные файлы. Если что-то пошло не так — приходит уведомление об ошибке.
Запусти скрипт вручную прямо сейчас и убедись что файлы пришли. Не откладывай — бэкапы нужны именно до того как всё сломалось, а не после.
Оставайтесь на связи
Рецепты от IT-боли. Без воды, без рекламы, без маркетинговой шелухи.
Подписаться на IT-Аптеку →




по этой ссылке не работает скрипт бекапа https://it-apteka.com/rezervnoe-kopirovanie-mikrotik-routeros-7-v-telegram-avtomatizacija-za-20-minut/
ругается на 22 строку http-content-type=»multipart/form-data» \
expected end of command
Приветствую, спасибо за обратную связь.
В RouterOS 7 /tool fetch не поддерживает параметр http-content-type как самостоятельный аргумент командной строки. Это не валидный параметр. RouterOS при использовании upload=yes сам выставляет нужный content-type. Поэтому строка http-content-type=»multipart/form-data» \ вызывает expected end of command.Дополнительно: http-data и upload=yes нельзя использовать одновременно — это разные режимы. Chat_id нужно передавать как query-параметр в URL при upload.
Переписал, исправил, если что пишите.