mikrotik-doh-failover — это семь .rsc-файлов, которые настраивают на RouterOS один DoH-апстрим с проверкой сертификата, заставляют локальную сеть спрашивать резолвер роутера и добавляют планировщик, который сам переключается на второй DoH-эндпоинт, проверяет переключение и откатывается, если резерв не резолвит. Проект вырос из статьи «Архитектура отказоустойчивого DNS-over-HTTPS в RouterOS» и решает ровно ту задачу, на которой обычно всё ломается: не «включить DoH на MikroTik», а «не потерять разрешение имён и не принять заглушку за рабочий ответ». Версия 0.2.0, вышедшая 26 октября 2026 года, поменяла саму логику проверки: теперь DoH на MikroTik оценивается по содержимому ответа, аварийным резервом служит второй 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 # сколько попыток израсходовано
Замеры и цифры
Все числа ниже — из репозитория и его документов, снятые на тестовом стенде и на парке. Это не бенчмарк производительности: у набора нет производительности, есть поведение в отказах.
| Что измерено | Значение | Где и когда |
|---|---|---|
| Скриптов 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 у репозитория нет.
Чек-лист внедрения
- Снять откат:
/export file=before-dohи/system backup save name=before-doh. - Проверить предусловия: версия RouterOS,
device-mode, синхронизация NTP, имена бриджа и списков интерфейсов. - Импортировать
00-install-ca.rscи убедиться, что в/certificate print where trusted=yesесть SSL.com TLS ECC Root CA 2022. - Импортировать
01и02, затем проверить::put [:resolve example.com]даёт реальные адреса,/ip firewall nat print where comment~"force DNS"показывает два правила redirect. - Запустить монитор вручную (
/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научила этому лучше любого руководства.
Связанные материалы
- mikrotik-doh-failover — репозиторий — скрипты, документация, примеры и
AGENTS.md. - Релиз v0.2.0 — заметки о смене логики проверки и замеры с трёх точек.
- mikrotik-doh-failover v0.1.0 — первый релиз — разбор первой версии: импорт CA, принудительный DNS, планировщик.
- docs/troubleshooting.md §6.10 — «сайты не открываются, а резолвер здоров»: пара-заглушка и три способа её обойти.
- «Архитектура отказоустойчивого DNS-over-HTTPS в RouterOS» — статья, для которой этот набор собран как воспроизводимая часть.
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-рукопожатие, а не авария;
- если команда падает — остановиться и показать команду, вывод и код возврата.