mikrotik-doh-failover — это семь .rsc-файлов, которые настраивают на RouterOS один DoH-апстрим с проверкой сертификата, заставляют локальную сеть спрашивать резолвер роутера и добавляют планировщик, который сам переключается на второй DoH-эндпоинт, проверяет переключение и откатывается, если резерв не резолвит. Проект вырос из статьи «Архитектура отказоустойчивого DNS-over-HTTPS в RouterOS» и решает ровно ту задачу, на которой обычно всё ломается: не «включить DoH на MikroTik», а «не потерять разрешение имён и не принять заглушку за рабочий ответ». Версия 0.2.0, вышедшая 26 октября 2026 года, поменяла саму логику проверки: теперь DoH на MikroTik оценивается по содержимому ответа, аварийным резервом служит второй DoH-эндпоинт, а не открытый DNS.

mikrotik-doh-failover — обложка обзора
Семь .rsc-файлов: DoH, откат на второй эндпоинт, принудительный DNS и монитор

Ниже — как устроен набор, что именно он измеряет, где проходит граница его возможностей и как развернуть его так, чтобы не оставить сеть без DNS.

TL;DR: что это и как проверить за десять минут

  • Задача: держать DNS локальной сети на шифрованном апстриме MikroTik и переживать отказ этого апстрима без ручных действий.
  • Форма: только конфигурация — семь .rsc-скриптов, импортируемых по порядку, плюс сертификат. Пакетов, служб и внешних демонов нет.
  • Устройство: /ip dns с одним use-doh-server, статические bootstrap-записи, перехват 53-го порта на LAN, скрипт DNS_HealthMonitor_Failover и планировщик Scheduler_DNS_Health_Check с интервалом 3m.
  • Проверка: /certificate print where trusted=yes, затем :put [:resolve example.com] — реальные адреса вида 104.20.x, а не пара 8.6.112.0 / 8.47.69.0, и /log print where message~"DNS monitor".
  • Главное ограничение: автоматика требует device-mode=advanced; на home роутер отклоняет и планировщик, и /tool fetch, поэтому монитор запускается вручную.
  • Чего не делает: не блокирует клиентский DoH по 443 и DoT по 853, не добавляет DNSSEC и не спасает от «пары-заглушки», если до неё нет пути из вашей сети.

Проблема, которую это решает

RouterOS по умолчанию отправляет запросы локальной сети наружу открытым текстом. Включить DoH несложно — сложно не сломать при этом разрешение имён. Две ошибки встречаются чаще остальных. Первая: добавить несколько DoH-серверов через /ip dns static-server type=doh и ждать резервирования — такого синтаксиса в RouterOS нет, а use-doh-server поддерживает ровно один адрес. Вторая: включить verify-doh-cert=yes, не импортировав корневой сертификат. Встроенное хранилище доверия на 7.23 и 7.24 цепочку Cloudflare не покрывает, поэтому проверка не проходит и разрешение имён останавливается целиком — при этом роутер выглядит исправным, а сеть теряет DNS в пределах TTL кэша.

Есть и третья ошибка, которая не выглядит ошибкой вовсе. Здоровая с виду проверка «получили IP — значит работаем» пропускает подменённые и заглушечные ответы. Именно так случилось при развёртывании на сети филиала: страница, работавшая неделями, перестала открываться, а резолвер был совершенно здоров. Cloudflare отвечал парой 8.6.112.0 / 8.47.69.0, и до этой пары из сети филиала просто не было пути. Версия 0.1.0 считала любой валидный адрес признаком здоровья, поэтому авария была невидимой: монитор молчал, логи были чистые, а CDN не открывались.

Замеры 26 октября 2026 года с трёх точек показывают, что дело не в провайдере и не в фильтре:

Запрос Ответ
DoH, обычный эндпоинт, из российской сети сначала 104.26.x, примерно через 30 минут 8.6.112.0 / 8.47.69.0
DoH, Family-эндпоинт, та же точка 8.6.112.0 / 8.47.69.0
открытый DNS на 1.1.1.1 и 8.8.8.8, та же точка та же пара, Google ответил 8.6.112.5
те же вопросы из Германии 104.26.x, 172.66.x
curl --resolve example.com:443:8.6.112.0 с WAN роутера 200 с валидным сертификатом
то же с сети филиала за другим провайдером таймаут соединения

Вывод, который стоит держать в голове: пара настоящая, её отдаёт Cloudflare, и она недоступна из части сетей. Смена бренда резолвера не помогает — помогает доступность адресов.

Что такое mikrotik-doh-failover

Это конфигурация, а не программа: ничего не устанавливается, ни один процесс не работает вне роутера, а единственная исполняемая часть — запись планировщика, запускающая скрипт RouterOS каждые три минуты. Скрипты пишут только в собственную конфигурацию устройства: /certificate, /ip dns, /ip dns static, /ip firewall nat, /ip firewall filter, /system script, /system scheduler, при необходимости /caps-man и /ip dhcp-server network. Телеметрии, обратных вызовов и обращений в репозиторий нет; сеть нужна только двум DoH-эндпоинтам по TCP 443 и NTP-серверам по IP во время настройки.

flowchart TB
  FILES["routeros: 7 .rsc-файлов"] --> CA["00-install-ca.rsc: корневой CA в доверенные"]
  FILES --> DOH["01-configure-doh.rsc: DoH + bootstrap-записи"]
  FILES --> FW["02-security-policies.rsc: DNS из LAN на роутер"]
  FILES --> MON["05-dns-health-monitor.rsc: монитор и планировщик"]
  CERT["certs/cloudflare-doh-ca.crt"] --> CA
  NTP["NTP по IP-адресам"] --> CERT
  CA --> DNS["/ip dns роутера"]
  DOH --> DNS
  MON -->|"переключает use-doh-server"| DNS
  DNS --> PRIMARY["основной DoH: cloudflare-dns.com"]
  DNS -.->|"после переключения"| FALLBACK["резервный DoH: dns.google"]
Файл Что делает
routeros/00-install-ca.rsc импортирует корневой CA и помечает его trusted=yes
routeros/01-configure-doh.rsc один DoH-апстрим, bootstrap-записи для обоих имён, allow-remote-requests
routeros/02-security-policies.rsc перехват 53 (UDP и TCP) с LAN-бриджа, приём DNS из LAN и запрет из WAN
routeros/03-capsman.rsc необязательная привязка к одной конфигурации /caps-man
routeros/04-cert-update.rsc необязательное обновление CA
routeros/05-dns-health-monitor.rsc проверка ответов, переключение, откат, планировщик
routeros/config.example.rsc все настраиваемые значения одним справочником

Кроме скриптов в наборе два примера целиком (examples/cloudflare-standard.rsc — новое умолчание, examples/cloudflare-family.rsc — фильтрация по желанию), три документа (docs/architecture.md, docs/verification.md, docs/troubleshooting.md), три схемы Mermaid и сам корневой сертификат certs/cloudflare-doh-ca.crt: SSL.com TLS ECC Root CA 2022, 1533 байта, издатель AAA Certificate Services, действует до 1 января 2029 года, SHA-256 24B226BCA66D2FD890EA56CF56D9DDD177FD5ED57FF9F9859B073057A96A881B.

Возможности: DoH на MikroTik без ежедневного ручного вмешательства

Возможности набора удобно разложить по задачам, а не по файлам.

Шифрование и доверие

Что На какой вопрос отвечает
Один активный DoH-апстрим с verify-doh-cert=yes «трафик до резолвера действительно шифруется и сертификат проверен?»
Явный импорт корневого CA «почему резолвинг умер, хотя всё настроено?» — потому что цепочка не покрыта встроенным хранилищем
Матрица провайдеров в config.example.rsc «какие три значения меняются при смене провайдера?» — URL, обычные servers и корневой CA

Отказоустойчивость

Что На какой вопрос отвечает
Переключение на второй DoH-эндпоинт (dns.google) «что произойдёт, если основной провайдер недоступен?»
Проверка переключения и откат «а если резерв отвечает, но не резолвит?» — откат на прежний эндпоинт и запись в лог
Ограничение числа попыток на одну аварию «не будет ли монитор дёргать роутер бесконечно?»
Bootstrap-записи для обоих имён «как проверить резерв, если резолвер уже мёртв?» — по закреплённым адресам

Диагностика

Что На какой вопрос отвечает
Три канарейки и оценка по содержимому «ответ настоящий или заглушка?»
Состояния healthy, stub, unreachable в логе «что именно случилось и когда?»
Проверка часов перед действиями «почему сертификат не проверяется?» — потому что дата неверна
docs/troubleshooting.md §6.10–§6.12 «сайты не открываются, а резолвер здоров — куда смотреть?»

Сеть и эксплуатация

Что На какой вопрос отвечает
Перехват UDP и TCP 53 через action=redirect «клиент обойдёт настройку своим резолвером?» — классический DNS не обойдёт
Приём DNS из LAN и запрет из WAN «резолвер открыт наружу?» — нет, снаружи запросы отбрасываются
Суженная политика скрипта read,write,policy,test «какие права нужны монитору?» — минимальные, без ftp, reboot, password
Возможность отключить фильтрацию «почему блокируются рабочие домены?» — потому что включён Family, а не standard

Как это устроено внутри

Порядок применения — не рекомендация, а часть конструкции: каждый шаг опирается на предыдущий, и проверка выполняется после каждого. Сначала снимается откат (/export file=before-doh и /system backup save name=before-doh), затем настраивается NTP по IP-адресам — намеренно мимо DNS, который этот же набор и защищает. Дальше импортируется CA, и только после него включается use-doh-server с проверкой сертификата: без доверенного корня проверка не проходит и сеть остаётся без разрешения имён.

После этого настраивается сеть: dstnat action=redirect для UDP и TCP 53 с LAN-бриджа, приём DNS из локальной сети и запрет из WAN. И последним шагом ставится монитор — сначала его запускают руками, и только убедившись, что он пишет ожидаемое, добавляют планировщик.

flowchart LR
  TICK["планировщик: каждые 3 минуты"] --> CLOCK{"часы верны?"}
  CLOCK -- нет --> STOP["clock looks wrong: стоп без переключений"]
  CLOCK -- да --> PROBE["три канарейки через :resolve"]
  PROBE --> JUDGE{"ответы настоящие?"}
  JUDGE -- да --> OK["healthy: ничего не меняем"]
  JUDGE -- "пара-заглушка" --> STUB["stub: пишем один раз, не переключаем"]
  JUDGE -- нет --> ALIVE{"основной эндпоинт отвечает по /tool fetch?"}
  ALIVE -- да --> OK
  ALIVE -- нет --> SWITCH["переключить на резервный DoH"]
  SWITCH --> VERIFY{"резервный резолвит?"}
  VERIFY -- да --> KEEP["оставить резервный, запись warning"]
  VERIFY -- нет --> ROLLBACK["откат на прежний, запись error"]

Логика монитора в версии 0.2.0 изменилась принципиально. Он больше не переключает use-doh-server, чтобы «проверить» канал: оба эндпоинта опрашиваются через /tool fetch по их DNS-JSON API, то есть обычная проверка не выводит сеть из шифрованного режима даже на секунду.

/tool fetch url="https://cloudflare-dns.com/dns-query?name=example.com&type=A" \
    http-header-field="accept: application/dns-json" dst-path="doh.json" mode=https
# ожидается: code 200, в теле "Status":0

Ответ 400 на POST или 405 на GET — это не авария, а успешное TLS-рукопожатие с неверной формой запроса. Затем монитор судит о состоянии по трём канарейкам и по содержимому ответа: пустой ответ, 0.0.0.0 и пара-заглушка 8.6.112.0 / 8.47.69.0 считаются непригодными. При отказе основного эндпоинта он переключается на резервный, проверяет, что тот действительно резолвит имя, и откатывается, если нет. Число попыток на одну аварию ограничено.

Состояние живёт в глобальных переменных RouterOS (DNSMonitorState, DNSFailoverAttempts), а не в файле: после перезагрузки монитор начинает с чистого состояния и пишет первый переход заново. Старая переменная DNSCurrentMode из версии 0.1.0 больше не используется.

Переходы видны в логе по фразам, и это самый быстрый способ понять, что произошло:

Что случилось Строка в логе Что делает монитор
ответы настоящие answers look sane (N of 3) ничего, пишет один раз на переход
пришла пара-заглушка answers are the stub pair … не переключает: резерв вернёт ту же пару
основной не отвечает primary DoH unreachable опрашивает резервный и переключается
резерв заработал switched to fallback DoH … example.com -> … оставляет резервный адрес в use-doh-server
оба недоступны both endpoints unreachable — keeping the current configuration ничего не меняет
резерв не резолвит fallback DoH did not resolve either — rolled back возвращает прежний эндпоинт
сбиты часы clock looks wrong … certificate validation cannot succeed останавливается, не тратя попытки

Пример конверта состояния, как его видит администратор при ручном запуске:

:put $DNSMonitorState      # healthy | stub | unreachable
:put $DNSFailoverAttempts  # сколько попыток израсходовано

Замеры и цифры

Все числа ниже — из репозитория и его документов, снятые на тестовом стенде и на парке. Это не бенчмарк производительности: у набора нет производительности, есть поведение в отказах.

mikrotik-doh-failover: ключевые числа
Ключевые числа набора: семь скриптов, два эндпоинта, три канарейки и три минуты между проверками
Что измерено Значение Где и когда
Скриптов RouterOS 7 routeros/, дерево v0.2.0
Примеров конфигурации 2 (standard, family) examples/, v0.2.0
Документов и схем 3 документа, 3 схемы docs/, diagrams/
Проверенных устройств 6 моделей на 2 версиях RouterOS (7.23.1, 7.24.5) README, таблица совместимости
Импорт корневого CA 118 сертификатов, trusted=yes установлен парк, 22.10.2026
Фильтр Family работает 0.0.0.0 на всех пяти устройствах парка 22.10.2026
JSON-проба эндпоинта code 200, тело 251 байт, "Status":0 найдено 26.10.2026, 7.23.1, hAP ax²
Переключение на резерв «switched to fallback DoH», use-doh-server = резервный 26.10.2026, стенд
Откат при мёртвом резерве «both endpoints unreachable — keeping the current configuration» 26.10.2026, стенд
Проверка часов «clock looks wrong … certificate validation cannot succeed», без действий 26.10.2026, стенд
Quad9 и JSON-проба DoH unable to decode BASE64-URL — не опрашивается 26.10.2026
:resolve с параметром server= поддерживается, timeout= даёт bad parameter 22.10.2026, 7.23.1 и 7.24.5

Оговорка о границах замера: цифры по парку относятся к версии 0.1.0, а проверки переключения и отката — к 0.2.0 на одном тестовом устройстве. Поведение на RouterOS 7.20–7.22 в репозитории не документировано: бейдж обещает 7.20+, измерения сделаны на 7.23.1 и 7.24.5.

Почему это круто

  • Проверка судит ответ, а не его тип. Именно это отличие поймало реальную аварию: заглушечная пара выглядит как валидный A-адрес, и только оценка содержимого отличает её от рабочего ответа.
  • Резерв — тоже DoH. Откат на открытый DNS в российских сетях бессмысленен: замеры показали подмену даже для запросов напрямую на 1.1.1.1 и 8.8.8.8, поэтому «аварийный» открытый канал превращал видимый отказ в тихий.
  • Проверка не выводит сеть из шифрованного режима. Опрос идёт через /tool fetch по JSON-API, а не через временную очистку use-doh-server, как было в 0.1.0.
  • Неудачное переключение откатывается. Роутер не остаётся на мёртвом эндпоинте: сначала проверяется резерв, потом выполняется переключение, при неудаче возвращается прежний адрес.
  • Часы проверяются до всего остального. Со сбитой датой проверка сертификата не пройдёт никогда, и без этой проверки монитор вечно сообщал бы «DoH недоступен».
  • Права скрипта сужены. Политика read,write,policy,test вместо полного набора — монитору не нужны ftp, reboot, password, sniff и romon.
  • Всё в конфигурации, ничего в пакетах. Разворачивается импортом файлов, откатывается экспортом конфигурации; следов в системе не остаётся.
  • Ограничения названы прямо. Клиентский DoH по 443 не блокируется, DNSSEC не добавляется, device-mode=home отключает автоматику — это записано в документации, а не выясняется в бою.

Установка

Требование Почему
RouterOS 7.20 или новее нужны use-doh-server, verify-doh-cert и работа с сертификатами
Синхронизированный NTP проверка TLS требует верного времени
device-mode известен на home планировщик и /tool fetch отклоняются
Административная сессия импорт пишет в хранилище сертификатов
Сертификат в файлах роутера import file-name= читает файловую систему устройства, а не репозиторий
Имена интерфейсов совпадают правило на несуществующий интерфейс добавляется молча и не работает
Окно обслуживания неверный CA или недоверенная цепочка останавливает разрешение имён во всей сети

Файлы берутся из репозитория с закреплением на тег: ветка main уходит вперёд, тег — нет.

git clone --depth 1 --branch v0.2.0 https://github.com/paulmann/mikrotik-doh-failover.git
curl -fLO https://raw.githubusercontent.com/paulmann/mikrotik-doh-failover/v0.2.0/certs/cloudflare-doh-ca.crt

Дальше сертификат и нужные .rsc загружаются в корень файловой системы роутера, и выполняется импорт по порядку.

/export file=before-doh
/system backup save name=before-doh
/import file-name=00-install-ca.rsc
/import file-name=01-configure-doh.rsc
/import file-name=02-security-policies.rsc
/import file-name=05-dns-health-monitor.rsc

03-capsman.rsc нужен только для устаревшего контроллера /caps-man, 04-cert-update.rsc — при плановой смене CA. Перед повторным импортом стоит посмотреть, что уже есть в конфигурации: 01 и 02 не идемпотентны и добавят вторую запись.

/ip dns static print where comment="DoH bootstrap"
/ip firewall nat print where comment~"force DNS"
/ip firewall filter print where comment~"DNS"
/system script print where name="DNS_HealthMonitor_Failover"

Настройка

Все настраиваемые значения собраны в routeros/config.example.rsc. Это справочник и заготовка для копирования: RouterOS не умеет подключать общий файл, поэтому каждый скрипт несёт свой блок # ===== CONFIG =====, и править надо именно его, а не тело скрипта.

flowchart TD
  CFG["routeros/config.example.rsc: глобальные значения"] --> FILT{"фильтрация нужна?"}
  FILT -- нет --> STD["standard: cloudflare-dns.com, 1.1.1.1 и 1.0.0.1, filtering false"]
  FILT -- да --> FAM["family или security: 1.1.1.3 или 1.1.1.2, filtering true"]
  CFG --> PROV["резервный провайдер: dns.google"]
  CFG --> IFACE["имена: bridge, LAN, WAN, конфигурация CAPsMAN"]
  STD --> ROOT["свой корневой CA у каждого провайдера"]
  FAM --> ROOT
  PROV --> BOOT["bootstrap-записи для обоих имён"]
Значение По умолчанию в 0.2.0 Зачем меняют
dohUrl https://cloudflare-dns.com/dns-query сменить провайдера
dohHost cloudflare-dns.com имя для bootstrap-записей
dohServers 1.1.1.1,1.0.0.1 обычный DNS как bootstrap, не как рабочий откат
filtering false включить Family или Security осознанно
dohUrlB https://dns.google/dns-query резервный эндпоинт
probeUrlA, probeUrlB JSON-API Cloudflare и Google проверка эндпоинтов без переключения
bridge, lanList, wanList bridge, LAN, WAN имена в вашей конфигурации
capConfig, capBridge, dnsIp cfg1, bridge-local, 192.168.88.1 интеграция с CAPsMAN

Смена провайдера — это всегда три значения: URL, обычные servers и корневой сертификат. Проверка сертификата против чужого корня откажет точно так же, как при полном отсутствии CA. И отдельно про фильтрацию: по умолчанию она выключена намеренно. Замеры 26 октября показали, что пара-заглушка приходит и от обычного эндпоинта, то есть это не эффект фильтра, а свойство сети; но включать Family «на всякий случай» всё равно не стоит — она меняет ответы для рабочих имён.

Подводные камни

  • device-mode=home отключает автоматику. Роутер отклоняет /system scheduler add и /tool fetch с not allowed by device-mode; без fetch монитор сообщает, что оба эндпоинта недоступны, и оставляет текущую конфигурацию. Перевод в advanced — решение владельца с подтверждением на устройстве и перезагрузкой.
  • Роутер не может проверить доступность пары-заглушки из своей сети. Это делается с клиента: nslookup и curl --resolve с нужным адресом. Ответ 302 за десятые доли секунды означает, что путь есть; таймаут — что это и есть ваша авария.
  • Открытый DNS не спасает. Замеры показали подмену даже при запросах напрямую на 1.1.1.1 и 8.8.8.8, поэтому версия 0.2.0 убрала открытый канал из роли рабочего резерва.
  • Quad9 не годится резервом при JSON-проверке. Его эндпоинт отвечает DoH unable to decode BASE64-URL; как апстрим он работает, но опросить его этим способом нельзя.
  • /ip dns static сильнее ответа DoH. Закреплённое имя обходит фильтр — это и дефект диагностики, и рабочий приём: закрепить доступный адрес для имени, которое резолвится в заглушку.
  • use-doh-server не откатывается на servers сам. Если оба эндпоинта мертвы, разрешение имён останавливается; именно поэтому монитор — часть набора, а не украшение.
  • Чего набор не делает вовсе: не блокирует клиентский DoH по 443 и жёстко прописанные резолверы, не добавляет DNSSEC, не поддерживает несколько WAN и IPv6-апстрим; поведение на 7.20–7.22 не документировано, автоматических тестов и CI у репозитория нет.

Чек-лист внедрения

  1. Снять откат: /export file=before-doh и /system backup save name=before-doh.
  2. Проверить предусловия: версия RouterOS, device-mode, синхронизация NTP, имена бриджа и списков интерфейсов.
  3. Импортировать 00-install-ca.rsc и убедиться, что в /certificate print where trusted=yes есть SSL.com TLS ECC Root CA 2022.
  4. Импортировать 01 и 02, затем проверить: :put [:resolve example.com] даёт реальные адреса, /ip firewall nat print where comment~"force DNS" показывает два правила redirect.
  5. Запустить монитор вручную (/system script run DNS_HealthMonitor_Failover), прочитать /log print where message~"DNS monitor" и только после этого включать планировщик.

Критерий «работает»: :resolve example.com возвращает адреса вида 104.20.x или 172.66.x, :put $DNSMonitorState показывает healthy, в логе нет connection error, а :resolve pornhub.com с обычным резолвером даёт настоящий адрес — 0.0.0.0 появляется только при включённой фильтрации.

FAQ

Нужно ли ставить пакет или службу на роутер?

Нет. Это только конфигурация: импорт .rsc-файлов, сертификат в файловой системе и одна запись планировщика. Пакеты, контейнеры и внешние демоны не используются, откат — импорт ранее снятого экспорта.

Почему резервный DoH не сделан через два use-doh-server?

Потому что RouterOS поддерживает ровно один use-doh-server, а синтаксис static-server type=doh не существует. Резерв в наборе — второй DoH-эндпоинт, на который монитор переключает use-doh-server после проверки.

Почему проверка не переключает use-doh-server, как раньше?

Чтобы обычная проверка не выводила сеть из шифрованного режима. В 0.2.0 оба эндпоинта опрашиваются через /tool fetch по DNS-JSON API; временная очистка use-doh-server больше не используется.

Что значит «пара-заглушка» и почему монитор не переключается?

Это адреса 8.6.112.0 / 8.47.69.0, которые Cloudflare отдаёт части сетей. Второй эндпоинт вернёт ту же пару, поэтому переключение бессмысленно: монитор помечает состояние stub и пишет об этом один раз, а лечится это доступностью адресов — туннелем, закреплением адреса или сменой точки выхода.

Можно ли поставить это на RouterOS 7.20–7.22?

Заявленная граница — 7.20+, но замеры сделаны на 7.23.1 и 7.24.5, поведение на 7.20–7.22 в репозитории не документировано. На такой версии сначала проверяют импорт CA и :resolve на одном устройстве.

Почему в инструкции для агентов остались значения от 0.1.0?

Так и есть: в AGENTS.md версии 0.2.0 раздел 3.1 закрепляет тег v0.1.0, а раздел 5 ожидает servers=1.1.1.3,1.0.0.3 и переменную DNSCurrentMode, которой в 0.2.0 уже нет. Сверяйте ожидаемые значения по docs/verification.md и routeros/config.example.rsc — там умолчания 0.2.0.

Итог

Набор решает узкую задачу, но решает её честно: не обещает резервирования там, где RouterOS его не умеет, не выдаёт заглушку за рабочий ответ и не оставляет роутер на мёртвом эндпоинте после неудачного переключения. Главная ценность версии 0.2.0 — именно смена критерия здоровья: проверка стала судить ответ по содержимому, и это единственное, что поймало бы аварию с парой 8.6.112.0 / 8.47.69.0. Если у вас MikroTik работает шлюзом и DNS идёт через него, набор стоит развернуть на одном устройстве, прогнать чек-лист и только потом тиражировать: цена ошибки здесь — вся локальная сеть без разрешения имён.

Цитата: Отказоустойчивость DNS начинается не с включения DoH, а с честного ответа на вопрос, что считать здоровым ответом — и заглушка 8.6.112.0 научила этому лучше любого руководства.

Связанные материалы

LLM Summary

  • Тема: mikrotik-doh-failover — набор .rsc-скриптов для MikroTik RouterOS: шифрованный DNS с проверкой сертификата, автоматическое переключение и откат.
  • Что делает: настраивает один DoH-апстрим, перехватывает классический DNS локальной сети, ставит монитор с планировщиком каждые три минуты и умеет возвращаться на основной эндпоинт после восстановления.
  • Форма: только конфигурация — семь скриптов, два примера, три документа, три схемы и корневой сертификат; пакетов и служб нет.
  • Устройство: /ip dns с одним use-doh-server, bootstrap-записи для основного и резервного имён, dstnat action=redirect для UDP и TCP 53, скрипт DNS_HealthMonitor_Failover с политикой read,write,policy,test.
  • Ключевые команды: /import file-name=01-configure-doh.rsc, /ip dns cache flush, :put [:resolve example.com], /system script run DNS_HealthMonitor_Failover, /log print where message~"DNS monitor".
  • Требования: RouterOS 7.20+ (проверено 7.23.1 и 7.24.5), синхронизированный NTP, device-mode=advanced для планировщика, административный доступ и сертификат в файлах роутера.
  • Замеры: JSON-проба даёт code 200 и Status:0; пара-заглушка 8.6.112.0/8.47.69.0 приходит из части сетей и не переключается; импорт CA на парке дал 118 сертификатов; фильтр Family давал 0.0.0.0 на пяти устройствах.
  • Ограничения: клиентский DoH и DoT не блокируются, DNSSEC не добавляется, /ip dns static сильнее ответа DoH, device-mode=home отключает автоматику, Quad9 не опрашивается JSON-пробой.
  • Ссылки: https://github.com/paulmann/mikrotik-doh-failover, https://github.com/paulmann/mikrotik-doh-failover/releases/tag/v0.2.0

Промт для агента (установка и настройка)

Готовый промт для AI-агента: скопируйте блок целиком кнопкой и отдайте своему ассистенту. Команды взяты из AGENTS.md репозитория, а ожидаемые значения приведены к умолчаниям версии 0.2.0 по routeros/config.example.rsc и docs/verification.md — в самом AGENTS.md разделы 3.1 и 5 ещё описывают 0.1.0.

Задача: развернуть mikrotik-doh-failover 0.2.0 на устройстве MikroTik RouterOS и доказать, что разрешение имён работает и переживает отказ основного эндпоинта.

Материалы:
- репозиторий: https://github.com/paulmann/mikrotik-doh-failover
- релиз: https://github.com/paulmann/mikrotik-doh-failover/releases/tag/v0.2.0
- инструкция для агентов: https://github.com/paulmann/mikrotik-doh-failover/blob/main/AGENTS.md
- проверки подсистем и чек-лист отказа: docs/verification.md
- разбор отказов: docs/troubleshooting.md, разделы 6.10-6.12

Предусловия (AGENTS.md §2). Непройденная строка — стоп, а не предупреждение:
/system resource print
/system ntp client print
/system device-mode print
/interface bridge print
/interface list print
/export file=before-doh
/system backup save name=before-doh

Получить файлы, закрепив тег (в AGENTS.md §3.1 указан v0.1.0 — берём актуальный):
git clone --depth 1 --branch v0.2.0 https://github.com/paulmann/mikrotik-doh-failover.git
curl -fLO https://raw.githubusercontent.com/paulmann/mikrotik-doh-failover/v0.2.0/certs/cloudflare-doh-ca.crt

Сверить сертификат до импорта (§3.3): 1533 байта, CN=SSL.com TLS ECC Root CA 2022, SHA-256 24B226BCA66D2FD890EA56CF56D9DDD177FD5ED57FF9F9859B073057A96A881B. Другой отпечаток — остановиться. Файлы .crt и .rsc загружаются в корень Files роутера: import file-name= ищет там.

Применить по порядку (§4), после каждого шага — проверка:
/import file-name=00-install-ca.rsc
/import file-name=01-configure-doh.rsc
/import file-name=02-security-policies.rsc
/import file-name=05-dns-health-monitor.rsc

03-capsman.rsc — только для устаревшего /caps-man; 04-cert-update.rsc не нужен, пока корневой CA действителен до 2029-01-01.

Ожидаемые значения 0.2.0 (умолчание — обычный Cloudflare, без фильтрации):
/certificate print where trusted=yes
/ip dns print
/ip dns static print where comment~"DoH bootstrap"
/system clock print
/system ntp client print
/ip firewall nat print where comment~"force DNS"
/ip firewall filter print where comment~"DNS"
/ip dns cache flush
:put [:resolve example.com]
:put [:resolve pornhub.com]
/system script run DNS_HealthMonitor_Failover
/log print where message~"DNS monitor"
/log print where message~"connection error"

Что считать успехом: SSL.com в trusted=yes; servers=1.1.1.1,1.0.0.1 и use-doh-server с адресом cloudflare-dns.com; по две bootstrap-записи для cloudflare-dns.com и dns.google; :resolve example.com даёт 104.20.x или 172.66.x, а не пару 8.6.112.0 и 8.47.69.0; состояние монитора healthy, в логе «answers look sane»; строк connection error нет.

Проверка отказа (docs/verification.md, сценарии 3-6): поставить заведомо мёртвый основной эндпоинт, выполнить монитор, увидеть переключение на резерв; затем сделать мёртвым и резерв и убедиться, что конфигурация не изменилась («both endpoints unreachable — keeping the current configuration»). После проверки вернуть рабочие значения:
/ip dns set use-doh-server="https://cloudflare-dns.com/dns-query" verify-doh-cert=yes
/ip dns cache flush

Откат, если что-то пошло не так (§8):
/ip dns set use-doh-server=""
/ip dns cache flush
/ip firewall nat remove [find comment~"force DNS"]
/ip firewall filter remove [find comment~"DNS"]
/ip dns static remove [find comment="DoH bootstrap"]
/system scheduler remove [find name="Scheduler_DNS_Health_Check"]
/system script remove [find name="DNS_HealthMonitor_Failover"]
/certificate remove [find where name~"cloudflare-doh-ca"]
/import file-name=before-doh.rsc

Ограничения:
- одно устройство за раз: сломанный шаг с CA на десяти роутерах — это десять сетей без DNS;
- не выполнять /system reset-configuration и не удалять правила через [find] без фильтра по comment;
- не менять device-mode: это решение владельца, нужны подтверждение на устройстве и перезагрузка;
- не проверять DoH через /tool fetch к /dns-query по POST: 400 или 405 — успешное TLS-рукопожатие, а не авария;
- если команда падает — остановиться и показать команду, вывод и код возврата.