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

MikroTik REST API — автоматизация через HTTP

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

RouterOS 7 представила полноценный REST API, позволяющий управлять маршрутизатором через стандартные HTTP-запросы. Это открывает двери для интеграции MikroTik с любыми системами: мониторинг через Python-скрипты, управление из веб-приложений на Node.js, автоматизация через CI/CD пайплайны. REST API работает поверх HTTPS, использует Basic Auth для аутентификации и возвращает данные в JSON. В этом руководстве разберём все аспекты REST API: включение, аутентификацию, CRUD-операции с примерами curl, автоматизацию на Python и JavaScript, а также сравнение REST API с альтернативными способами программного доступа к RouterOS.

Описание

Что такое REST API в RouterOS

REST API — это HTTP-интерфейс, который транслирует HTTP-запросы в команды RouterOS CLI. Каждый путь в API соответствует пути в CLI:

CLI-командаREST API URL
/ip/address/printGET /rest/ip/address
/ip/firewall/filter/printGET /rest/ip/firewall/filter
/interface/printGET /rest/interface
/system/identity/printGET /rest/system/identity
/system/rebootPOST /rest/system/reboot

REST API доступен начиная с RouterOS 7.1beta4 и стабилизирован в 7.x ветке. В RouterOS 7.20+ он полностью готов к production-использованию.

Архитектура

code
HTTP Client ──[HTTPS, порт 443]──> RouterOS Web Service ──> REST Handler ──> CLI Engine
                                                                                  │
                                                                           ┌──────┼──────┐
                                                                           │      │      │
                                                                        Config   State  Actions

REST API использует тот же веб-сервер, что и WebFig. Запросы обрабатываются через /rest/ prefix и транслируются во внутренние CLI-команды.

HTTP-методы и CRUD

HTTP-методRouterOS-операцияОписание
GETprintЧтение данных (списки, свойства)
PUTaddСоздание нового элемента
PATCHsetИзменение существующего элемента
DELETEremoveУдаление элемента
POSTлюбая командаВыполнение произвольной команды

REST API vs RouterOS API (8728) vs SSH

ПараметрREST APIRouterOS APISSH
Порт443 (HTTPS)8728 / 8729 (TLS)22
ПротоколHTTP/HTTPSБинарныйSSH
АутентификацияBasic AuthAPI loginКлючи/пароль
Формат данныхJSONБинарные sentenceТекст
Клиентские библиотекиЛюбой HTTP-клиентlibrouteros, routeros-apiparamiko, ssh2
OverheadСредний (HTTP)Минимальный (binary)Средний (SSH)
StreamingНетДа (listen)Да (watch)
Firewall-совместимостьЛегко (HTTPS)Нужен открытый порт 8728Легко (SSH)
ИнтеграцияЛюбой язык/платформаНужна специальная библиотекаЛюбой SSH-клиент
Подходит дляWeb-интеграции, скрипты, CI/CDВысокопроизводительные приложенияРучное управление, скрипты

Рекомендация: REST API — лучший выбор для интеграций и автоматизации. RouterOS API — для приложений с высокими требованиями к производительности (мониторинг с частым опросом). SSH — для разовых задач и скриптов.

Настройка

Шаг 1: включение HTTPS-сервиса

REST API работает через веб-сервис RouterOS. Для безопасности используйте HTTPS:

[admin@MikroTik] >
# Проверяем текущее состояние веб-сервисов
/ip/service/print

# Включаем HTTPS (www-ssl)
/ip/service/set www-ssl disabled=no

# Отключаем HTTP (небезопасный)
/ip/service/set www disabled=yes

# Ограничиваем доступ к API по IP
/ip/service/set www-ssl address=192.168.88.0/24,10.0.0.0/8

# Проверяем порт (по умолчанию 443)
/ip/service/print where name=www-ssl

Для HTTPS нужен SSL-сертификат. Можно использовать самоподписанный или Let's Encrypt:

[admin@MikroTik] >
# Генерируем самоподписанный сертификат (для тестов)
/certificate/add name=rest-api-cert \
  common-name=router.local \
  key-size=2048 \
  days-valid=3650 \
  key-usage=tls-server

/certificate/sign rest-api-cert

# Назначаем сертификат веб-сервису
/ip/service/set www-ssl certificate=rest-api-cert

Шаг 2: создание пользователя для API

Создайте отдельного пользователя с минимальными правами:

[admin@MikroTik] >
# Группа только для чтения (мониторинг)
/user/group/add name=api-read \
  policy=read,api,winbox,test,!write,!policy,!ftp,!reboot,!sensitive \
  comment="REST API read-only access"

# Группа для полного управления
/user/group/add name=api-full \
  policy=read,write,api,test,!policy,!ftp \
  comment="REST API full access"

# Пользователь для мониторинга (только чтение)
/user/add name=api-monitor \
  group=api-read \
  password="MonitorPass!2025" \
  address=192.168.88.0/24 \
  comment="REST API monitoring user"

# Пользователь для управления
/user/add name=api-admin \
  group=api-full \
  password="AdminApiPass!2025" \
  address=192.168.88.100/32 \
  comment="REST API admin user"

Шаг 3: первый запрос через curl

Базовый синтаксис: curl -k -u user:password https://router-ip/rest/path

Флаг -k пропускает проверку SSL-сертификата (для самоподписанных). В production используйте валидный сертификат.

[admin@MikroTik] >
# Эти команды выполняются на внешнем компьютере, не на MikroTik

# GET — получить identity роутера
# curl -k -u api-monitor:MonitorPass!2025 https://192.168.88.1/rest/system/identity

# GET — список всех интерфейсов
# curl -k -u api-monitor:MonitorPass!2025 https://192.168.88.1/rest/interface

# GET — IP-адреса
# curl -k -u api-monitor:MonitorPass!2025 https://192.168.88.1/rest/ip/address

# GET — таблица маршрутизации
# curl -k -u api-monitor:MonitorPass!2025 https://192.168.88.1/rest/ip/route

Шаг 4: CRUD-операции

GET — чтение данных:

[admin@MikroTik] >
# Все IP-адреса (эквивалент /ip/address/print)
# curl -k -u admin:pass https://192.168.88.1/rest/ip/address

# Ответ JSON:
# [
#   {".id":"*1","address":"192.168.88.1/24","network":"192.168.88.0",
#    "interface":"bridge","actual-interface":"bridge","disabled":"false",
#    "dynamic":"false","comment":"LAN"}
# ]

GET с фильтрацией (query parameters):

[admin@MikroTik] >
# Фильтр по имени интерфейса
# curl -k -u admin:pass "https://192.168.88.1/rest/interface?name=ether1"

# Фильтр — только активные интерфейсы
# curl -k -u admin:pass "https://192.168.88.1/rest/interface?running=true"

# Фильтр по нескольким условиям
# curl -k -u admin:pass "https://192.168.88.1/rest/ip/firewall/filter?chain=input&action=drop"

# Получить конкретный элемент по .id
# curl -k -u admin:pass "https://192.168.88.1/rest/ip/address/*1"

# Свойства — выбрать конкретные поля
# curl -k -u admin:pass "https://192.168.88.1/rest/interface?.proplist=name,type,running"

PUT — создание элемента:

[admin@MikroTik] >
# Добавить IP-адрес (эквивалент /ip/address/add)
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PUT \
#   -H "Content-Type: application/json" \
#   -d '{"address":"10.0.0.1/24","interface":"ether2","comment":"REST API added"}' \
#   https://192.168.88.1/rest/ip/address

# Ответ: {"ret":"*A"} — возвращает .id нового элемента

# Добавить firewall-правило
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PUT \
#   -H "Content-Type: application/json" \
#   -d '{"chain":"input","protocol":"tcp","dst-port":"8291","action":"accept","comment":"Allow Winbox"}' \
#   https://192.168.88.1/rest/ip/firewall/filter

# Добавить статический маршрут
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PUT \
#   -H "Content-Type: application/json" \
#   -d '{"dst-address":"10.10.0.0/16","gateway":"192.168.88.254","comment":"Office network"}' \
#   https://192.168.88.1/rest/ip/route

PATCH — изменение элемента:

[admin@MikroTik] >
# Изменить comment у IP-адреса (по .id)
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PATCH \
#   -H "Content-Type: application/json" \
#   -d '{"comment":"Updated via REST API"}' \
#   https://192.168.88.1/rest/ip/address/*1

# Отключить интерфейс
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PATCH \
#   -H "Content-Type: application/json" \
#   -d '{"disabled":"true"}' \
#   https://192.168.88.1/rest/interface/ether5

# Изменить identity роутера
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PATCH \
#   -H "Content-Type: application/json" \
#   -d '{"name":"office-router-01"}' \
#   https://192.168.88.1/rest/system/identity

DELETE — удаление элемента:

[admin@MikroTik] >
# Удалить IP-адрес по .id
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X DELETE \
#   https://192.168.88.1/rest/ip/address/*A

# Удалить firewall-правило
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X DELETE \
#   https://192.168.88.1/rest/ip/firewall/filter/*5

POST — выполнение команд:

[admin@MikroTik] >
# Перезагрузка роутера
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X POST \
#   https://192.168.88.1/rest/system/reboot

# Пинг хоста
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X POST \
#   -H "Content-Type: application/json" \
#   -d '{"address":"8.8.8.8","count":"4"}' \
#   https://192.168.88.1/rest/ping

# Создать бэкап
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X POST \
#   -H "Content-Type: application/json" \
#   -d '{"name":"api-backup"}' \
#   https://192.168.88.1/rest/system/backup/save

JSON-ответы и коды ошибок

Успешные ответы:

МетодHTTP-кодТело ответа
GET200JSON-массив элементов
PUT201{"ret":"*id"}
PATCH200Пустое тело
DELETE200Пустое тело
POST200JSON-результат команды

Ошибки:

HTTP-кодОписаниеПример
400Bad RequestНеверный формат JSON, неизвестное свойство
401UnauthorizedНеверный логин/пароль
404Not FoundНесуществующий путь или .id
405Method Not AllowedНеподдерживаемый HTTP-метод
500Internal ErrorОшибка на стороне RouterOS

Пример ошибки:

json
{
  "error": 400,
  "message": "input does not match any value of address",
  "detail": "failure: input does not match any value of address at ... (line 1 column 10)"
}

Python: мониторинг MikroTik через REST API

Полноценный скрипт мониторинга на Python:

python
#!/usr/bin/env python3
"""MikroTik REST API Monitor — мониторинг через REST API."""

import requests
import json
import time
from datetime import datetime
from urllib3.exceptions import InsecureRequestWarning

# Отключаем предупреждения о самоподписанном сертификате
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

class MikroTikAPI:
    def __init__(self, host, username, password, port=443, use_ssl=True):
        proto = "https" if use_ssl else "http"
        self.base_url = f"{proto}://{host}:{port}/rest"
        self.auth = (username, password)
        self.verify = False  # True для production с валидным сертификатом

    def get(self, path, params=None):
        """GET-запрос — чтение данных."""
        url = f"{self.base_url}/{path.strip('/')}"
        resp = requests.get(url, auth=self.auth, verify=self.verify, params=params)
        resp.raise_for_status()
        return resp.json()

    def put(self, path, data):
        """PUT-запрос — создание элемента."""
        url = f"{self.base_url}/{path.strip('/')}"
        resp = requests.put(url, auth=self.auth, verify=self.verify, json=data)
        resp.raise_for_status()
        return resp.json()

    def patch(self, path, data):
        """PATCH-запрос — изменение элемента."""
        url = f"{self.base_url}/{path.strip('/')}"
        resp = requests.patch(url, auth=self.auth, verify=self.verify, json=data)
        resp.raise_for_status()
        return resp.status_code

    def delete(self, path):
        """DELETE-запрос — удаление элемента."""
        url = f"{self.base_url}/{path.strip('/')}"
        resp = requests.delete(url, auth=self.auth, verify=self.verify)
        resp.raise_for_status()
        return resp.status_code

    def post(self, path, data=None):
        """POST-запрос — выполнение команды."""
        url = f"{self.base_url}/{path.strip('/')}"
        resp = requests.post(url, auth=self.auth, verify=self.verify, json=data or {})
        resp.raise_for_status()
        return resp.json() if resp.content else None


def monitor_router(api):
    """Сбор и вывод метрик роутера."""
    # Системная информация
    identity = api.get("system/identity")
    resource = api.get("system/resource")

    print(f"\n{'='*60}")
    print(f"Router: {identity['name']}")
    print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"{'='*60}")
    print(f"Board:    {resource[0]['board-name']}")
    print(f"Version:  {resource[0]['version']}")
    print(f"Uptime:   {resource[0]['uptime']}")
    print(f"CPU Load: {resource[0]['cpu-load']}%")

    total_mem = int(resource[0]['total-memory'])
    free_mem = int(resource[0]['free-memory'])
    used_pct = round((total_mem - free_mem) / total_mem * 100, 1)
    print(f"RAM Used: {used_pct}% ({(total_mem - free_mem) // 1048576}MB / {total_mem // 1048576}MB)")

    # Интерфейсы
    interfaces = api.get("interface")
    print(f"\nInterfaces ({len(interfaces)} total):")
    for iface in interfaces:
        status = "UP" if iface.get('running') == 'true' else "DOWN"
        print(f"  {iface['name']:20s} {iface['type']:15s} [{status}]")

    # IP-адреса
    addresses = api.get("ip/address")
    print(f"\nIP Addresses ({len(addresses)}):")
    for addr in addresses:
        print(f"  {addr['address']:20s} -> {addr['interface']}")

    # DHCP-лизы
    try:
        leases = api.get("ip/dhcp-server/lease")
        active = [l for l in leases if l.get('status') == 'bound']
        print(f"\nDHCP Leases: {len(active)} active / {len(leases)} total")
    except Exception:
        print("\nDHCP: not configured")

    # Firewall
    try:
        rules = api.get("ip/firewall/filter")
        print(f"\nFirewall Rules: {len(rules)} in filter")
    except Exception:
        pass


if __name__ == "__main__":
    api = MikroTikAPI(
        host="192.168.88.1",
        username="api-monitor",
        password="MonitorPass!2025"
    )

    try:
        monitor_router(api)
    except requests.exceptions.ConnectionError:
        print("ERROR: Cannot connect to router")
    except requests.exceptions.HTTPError as e:
        print(f"ERROR: {e.response.status_code} — {e.response.text}")

JavaScript/Node.js: управление из веб-приложения

Пример на Node.js с использованием fetch:

javascript
// mikrotik-rest-client.js
// Node.js 18+ (встроенный fetch)

class MikroTikREST {
  constructor(host, username, password) {
    this.baseUrl = `https://${host}/rest`;
    this.headers = {
      'Authorization': 'Basic ' + Buffer.from(`${username}:${password}`).toString('base64'),
      'Content-Type': 'application/json',
    };
    // Для самоподписанного сертификата в Node.js
    // process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
  }

  async get(path) {
    const resp = await fetch(`${this.baseUrl}/${path}`, {
      method: 'GET',
      headers: this.headers,
    });
    if (!resp.ok) throw new Error(`GET ${path}: ${resp.status} ${await resp.text()}`);
    return resp.json();
  }

  async create(path, data) {
    const resp = await fetch(`${this.baseUrl}/${path}`, {
      method: 'PUT',
      headers: this.headers,
      body: JSON.stringify(data),
    });
    if (!resp.ok) throw new Error(`PUT ${path}: ${resp.status} ${await resp.text()}`);
    return resp.json();
  }

  async update(path, data) {
    const resp = await fetch(`${this.baseUrl}/${path}`, {
      method: 'PATCH',
      headers: this.headers,
      body: JSON.stringify(data),
    });
    if (!resp.ok) throw new Error(`PATCH ${path}: ${resp.status} ${await resp.text()}`);
    return resp.status;
  }

  async remove(path) {
    const resp = await fetch(`${this.baseUrl}/${path}`, {
      method: 'DELETE',
      headers: this.headers,
    });
    if (!resp.ok) throw new Error(`DELETE ${path}: ${resp.status} ${await resp.text()}`);
    return resp.status;
  }
}

// Пример использования
async function main() {
  const router = new MikroTikREST('192.168.88.1', 'api-admin', 'AdminApiPass!2025');

  // Получить identity
  const identity = await router.get('system/identity');
  console.log('Router name:', identity.name);

  // Получить список интерфейсов
  const interfaces = await router.get('interface');
  interfaces.forEach(iface => {
    console.log(`${iface.name} (${iface.type}) - ${iface.running === 'true' ? 'UP' : 'DOWN'}`);
  });

  // Добавить IP-адрес
  const result = await router.create('ip/address', {
    address: '10.99.0.1/24',
    interface: 'ether3',
    comment: 'Added from Node.js',
  });
  console.log('Created with ID:', result.ret);

  // Удалить добавленный адрес
  await router.remove(`ip/address/${result.ret}`);
  console.log('Address removed');
}

main().catch(console.error);

Безопасность REST API

Рекомендации по безопасности:

[admin@MikroTik] >
# 1. Только HTTPS — отключаем HTTP
/ip/service/set www disabled=yes
/ip/service/set www-ssl disabled=no

# 2. Ограничиваем доступ по IP
/ip/service/set www-ssl address=192.168.88.100/32,10.0.0.50/32

# 3. Отдельный пользователь с минимальными правами
/user/group/add name=api-readonly \
  policy=read,api,!write,!policy,!test,!ftp,!reboot,!sensitive

/user/add name=api-reader group=api-readonly \
  password="ReadOnlyPass!2025" \
  address=192.168.88.100/32

# 4. Firewall — разрешаем HTTPS только с доверенных IP
/ip/firewall/filter/add \
  chain=input \
  protocol=tcp \
  dst-port=443 \
  src-address-list=api-clients \
  action=accept \
  comment="Allow REST API from trusted IPs"

/ip/firewall/filter/add \
  chain=input \
  protocol=tcp \
  dst-port=443 \
  action=drop \
  comment="Drop REST API from other IPs"

/ip/firewall/address-list/add \
  list=api-clients \
  address=192.168.88.100 \
  comment="Monitoring server"

# 5. Логирование API-доступа
/system/logging/add topics=web-proxy,info action=memory

Проверка

Базовая проверка доступности

[admin@MikroTik] >
# На роутере — проверяем что сервис запущен
/ip/service/print where name=www-ssl

# Проверяем сертификат
/certificate/print where name=rest-api-cert

# Проверяем пользователя
/user/print where name=api-monitor

# Проверяем группу и политики
/user/group/print where name=api-read

С внешнего компьютера:

[admin@MikroTik] >
# curl — проверка доступности
# curl -k -v https://192.168.88.1/rest/system/identity -u api-monitor:MonitorPass!2025

# Ожидаемый ответ:
# HTTP/1.1 200 OK
# Content-Type: application/json
# {"name":"MikroTik"}

Проверка CRUD-операций

[admin@MikroTik] >
# Тестовая последовательность: создать → прочитать → изменить → удалить

# 1. Создаём тестовый IP-адрес
# curl -k -u api-admin:AdminApiPass!2025 -X PUT \
#   -H "Content-Type: application/json" \
#   -d '{"address":"10.255.255.1/32","interface":"lo","comment":"REST API test"}' \
#   https://192.168.88.1/rest/ip/address
# Ответ: {"ret":"*B"}

# 2. Читаем созданный адрес
# curl -k -u api-admin:AdminApiPass!2025 https://192.168.88.1/rest/ip/address/*B

# 3. Изменяем комментарий
# curl -k -u api-admin:AdminApiPass!2025 -X PATCH \
#   -H "Content-Type: application/json" \
#   -d '{"comment":"Updated via REST"}' \
#   https://192.168.88.1/rest/ip/address/*B

# 4. Удаляем
# curl -k -u api-admin:AdminApiPass!2025 -X DELETE \
#   https://192.168.88.1/rest/ip/address/*B

Мониторинг производительности API

[admin@MikroTik] >
# Проверяем нагрузку на веб-сервис
/system/resource/print

# Смотрим активные подключения к порту 443
/ip/firewall/connection/print where dst-port=443

# Логи веб-сервера
/log/print where topics~"web-proxy"

Типичные ошибки

1. Ошибка 401 Unauthorized

code
HTTP/1.1 401 Unauthorized

Причины и решения:

[admin@MikroTik] >
# Проверяем что пользователь существует
/user/print where name=api-monitor

# Проверяем что группа имеет policy=api
/user/group/print detail where name=api-read
# Должно быть: policy=... api ...

# Проверяем ограничение по IP
/user/print detail where name=api-monitor
# address= должен включать IP клиента

# Проверяем что www-ssl включён
/ip/service/print where name=www-ssl
# disabled=no

2. Ошибка "connection refused" или "SSL handshake failed"

[admin@MikroTik] >
# www-ssl отключён
/ip/service/set www-ssl disabled=no

# Нет сертификата
/ip/service/print detail where name=www-ssl
# certificate= должен быть заполнен

# Генерируем и назначаем сертификат
/certificate/add name=api-cert common-name=router key-size=2048 days-valid=3650
/certificate/sign api-cert
/ip/service/set www-ssl certificate=api-cert

3. Ошибка 400 — неверное свойство

json
{"error":400,"message":"unknown parameter","detail":"unknown parameter (line 1 column 10)"}

Имена свойств в JSON должны точно соответствовать CLI:

[admin@MikroTik] >
# Неправильно: "srcAddress" (camelCase)
# Правильно: "src-address" (kebab-case, как в CLI)

# Проверяем доступные свойства
# curl -k -u admin:pass https://192.168.88.1/rest/ip/firewall/filter
# Посмотрите ключи в ответе — используйте точно такие же

4. Ошибка 404 — неверный путь

json
{"error":404,"message":"Not Found"}
[admin@MikroTik] >
# Путь должен точно соответствовать CLI
# Неправильно: /rest/ip/addresses (множественное число)
# Правильно:   /rest/ip/address

# Неправильно: /rest/system/resources
# Правильно:   /rest/system/resource

# Проверяем путь в CLI
/ip/address/print  # если работает — REST путь: /rest/ip/address

5. CORS-ошибки при вызове из браузера

RouterOS не отдаёт CORS-заголовки. Вызов REST API напрямую из браузерного JavaScript (другой домен) не работает. Решения:

  1. Прокси-сервер: настройте nginx/caddy прокси с CORS-заголовками
  2. Backend: вызывайте REST API с серверной стороны (Node.js, Python)
  3. Расширение браузера: только для разработки

6. Таймаут при большом количестве данных

[admin@MikroTik] >
# Если таблица маршрутизации или connection tracking огромная,
# запрос может зависнуть. Используйте фильтры:

# Вместо получения ВСЕХ соединений
# curl ... https://router/rest/ip/firewall/connection

# Фильтруйте по нужным полям
# curl ... "https://router/rest/ip/firewall/connection?src-address=192.168.88.100"
# curl ... "https://router/rest/interface?.proplist=name,running,type"

7. Безопасность — не используйте HTTP

[admin@MikroTik] >
# НИКОГДА не используйте REST API через HTTP (порт 80)
# Логин/пароль передаются в Base64 — легко перехватить

# Всегда HTTPS
/ip/service/set www disabled=yes
/ip/service/set www-ssl disabled=no

# Если используете самоподписанный сертификат в production:
# 1. Импортируйте CA-сертификат на клиентские машины
# 2. Или используйте Let's Encrypt (см. статью о Let's Encrypt)

8. Rate limiting — нет встроенного ограничения

RouterOS не имеет встроенного rate limiting для REST API. При большом количестве запросов роутер может перегрузиться:

[admin@MikroTik] >
# Ограничиваем количество подключений через firewall
/ip/firewall/filter/add \
  chain=input \
  protocol=tcp \
  dst-port=443 \
  connection-limit=10,32 \
  action=drop \
  comment="REST API: max 10 concurrent connections per IP"

# Мониторинг нагрузки
/system/resource/print
/ip/firewall/connection/print count-only where dst-port=443
[admin@MikroTik] >
HTTP Client ──[HTTPS, порт 443]──> RouterOS Web Service ──> REST Handler ──> CLI Engine
                                                                                  │
                                                                           ┌──────┼──────┐
                                                                           │      │      │
                                                                        Config   State  Actions
# Проверяем текущее состояние веб-сервисов
/ip/service/print

# Включаем HTTPS (www-ssl)
/ip/service/set www-ssl disabled=no

# Отключаем HTTP (небезопасный)
/ip/service/set www disabled=yes

# Ограничиваем доступ к API по IP
/ip/service/set www-ssl address=192.168.88.0/24,10.0.0.0/8

# Проверяем порт (по умолчанию 443)
/ip/service/print where name=www-ssl
# Генерируем самоподписанный сертификат (для тестов)
/certificate/add name=rest-api-cert \
  common-name=router.local \
  key-size=2048 \
  days-valid=3650 \
  key-usage=tls-server

/certificate/sign rest-api-cert

# Назначаем сертификат веб-сервису
/ip/service/set www-ssl certificate=rest-api-cert
# Группа только для чтения (мониторинг)
/user/group/add name=api-read \
  policy=read,api,winbox,test,!write,!policy,!ftp,!reboot,!sensitive \
  comment="REST API read-only access"

# Группа для полного управления
/user/group/add name=api-full \
  policy=read,write,api,test,!policy,!ftp \
  comment="REST API full access"

# Пользователь для мониторинга (только чтение)
/user/add name=api-monitor \
  group=api-read \
  password="MonitorPass!2025" \
  address=192.168.88.0/24 \
  comment="REST API monitoring user"

# Пользователь для управления
/user/add name=api-admin \
  group=api-full \
  password="AdminApiPass!2025" \
  address=192.168.88.100/32 \
  comment="REST API admin user"
# Эти команды выполняются на внешнем компьютере, не на MikroTik

# GET — получить identity роутера
# curl -k -u api-monitor:MonitorPass!2025 https://192.168.88.1/rest/system/identity

# GET — список всех интерфейсов
# curl -k -u api-monitor:MonitorPass!2025 https://192.168.88.1/rest/interface

# GET — IP-адреса
# curl -k -u api-monitor:MonitorPass!2025 https://192.168.88.1/rest/ip/address

# GET — таблица маршрутизации
# curl -k -u api-monitor:MonitorPass!2025 https://192.168.88.1/rest/ip/route
# Все IP-адреса (эквивалент /ip/address/print)
# curl -k -u admin:pass https://192.168.88.1/rest/ip/address

# Ответ JSON:
# [
#   {".id":"*1","address":"192.168.88.1/24","network":"192.168.88.0",
#    "interface":"bridge","actual-interface":"bridge","disabled":"false",
#    "dynamic":"false","comment":"LAN"}
# ]
# Фильтр по имени интерфейса
# curl -k -u admin:pass "https://192.168.88.1/rest/interface?name=ether1"

# Фильтр — только активные интерфейсы
# curl -k -u admin:pass "https://192.168.88.1/rest/interface?running=true"

# Фильтр по нескольким условиям
# curl -k -u admin:pass "https://192.168.88.1/rest/ip/firewall/filter?chain=input&action=drop"

# Получить конкретный элемент по .id
# curl -k -u admin:pass "https://192.168.88.1/rest/ip/address/*1"

# Свойства — выбрать конкретные поля
# curl -k -u admin:pass "https://192.168.88.1/rest/interface?.proplist=name,type,running"
# Добавить IP-адрес (эквивалент /ip/address/add)
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PUT \
#   -H "Content-Type: application/json" \
#   -d '{"address":"10.0.0.1/24","interface":"ether2","comment":"REST API added"}' \
#   https://192.168.88.1/rest/ip/address

# Ответ: {"ret":"*A"} — возвращает .id нового элемента

# Добавить firewall-правило
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PUT \
#   -H "Content-Type: application/json" \
#   -d '{"chain":"input","protocol":"tcp","dst-port":"8291","action":"accept","comment":"Allow Winbox"}' \
#   https://192.168.88.1/rest/ip/firewall/filter

# Добавить статический маршрут
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PUT \
#   -H "Content-Type: application/json" \
#   -d '{"dst-address":"10.10.0.0/16","gateway":"192.168.88.254","comment":"Office network"}' \
#   https://192.168.88.1/rest/ip/route
# Изменить comment у IP-адреса (по .id)
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PATCH \
#   -H "Content-Type: application/json" \
#   -d '{"comment":"Updated via REST API"}' \
#   https://192.168.88.1/rest/ip/address/*1

# Отключить интерфейс
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PATCH \
#   -H "Content-Type: application/json" \
#   -d '{"disabled":"true"}' \
#   https://192.168.88.1/rest/interface/ether5

# Изменить identity роутера
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X PATCH \
#   -H "Content-Type: application/json" \
#   -d '{"name":"office-router-01"}' \
#   https://192.168.88.1/rest/system/identity
# Удалить IP-адрес по .id
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X DELETE \
#   https://192.168.88.1/rest/ip/address/*A

# Удалить firewall-правило
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X DELETE \
#   https://192.168.88.1/rest/ip/firewall/filter/*5
# Перезагрузка роутера
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X POST \
#   https://192.168.88.1/rest/system/reboot

# Пинг хоста
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X POST \
#   -H "Content-Type: application/json" \
#   -d '{"address":"8.8.8.8","count":"4"}' \
#   https://192.168.88.1/rest/ping

# Создать бэкап
# curl -k -u api-admin:AdminApiPass!2025 \
#   -X POST \
#   -H "Content-Type: application/json" \
#   -d '{"name":"api-backup"}' \
#   https://192.168.88.1/rest/system/backup/save
#### Python: мониторинг MikroTik через REST API

Полноценный скрипт мониторинга на Python:
#### JavaScript/Node.js: управление из веб-приложения

Пример на Node.js с использованием `fetch`:
#### Безопасность REST API

Рекомендации по безопасности:
### Проверка

#### Базовая проверка доступности
С внешнего компьютера:
#### Проверка CRUD-операций
#### Мониторинг производительности API
### Типичные ошибки

#### 1. Ошибка 401 Unauthorized
Причины и решения:
#### 2. Ошибка "connection refused" или "SSL handshake failed"
#### 3. Ошибка 400 — неверное свойство
Имена свойств в JSON должны точно соответствовать CLI:
#### 4. Ошибка 404 — неверный путь

#### 5. CORS-ошибки при вызове из браузера

RouterOS не отдаёт CORS-заголовки. Вызов REST API напрямую из браузерного JavaScript (другой домен) не работает. Решения:

1. **Прокси-сервер**: настройте nginx/caddy прокси с CORS-заголовками
2. **Backend**: вызывайте REST API с серверной стороны (Node.js, Python)
3. **Расширение браузера**: только для разработки

#### 6. Таймаут при большом количестве данных
#### 7. Безопасность — не используйте HTTP
#### 8. Rate limiting — нет встроенного ограничения

RouterOS не имеет встроенного rate limiting для REST API. При большом количестве запросов роутер может перегрузиться:
Автоматизация / MikroTik REST API — автоматизация через HTTP