DNS: кешуючий резолвер Unbound — налаштуйте за 15 хвилин (і уникайте поширеної пастки)

Було корисно?

Проблеми з DNS не оголошують себе як проблеми з DNS. Вони проявляються як «сторінка входу повільна», «Kubernetes поводиться дивно», «apt не може завантажити пакунок» або «моніторинг зелений, але користувачі обурені». І коли ви нарешті придивляєтесь, виявляється, що кожен хост виконує власні рекурсивні запити через ненадійний шлях мережі, або ще гірше — ви побудували ланцюжок резолверів, який пожирає сам себе.

Unbound — це нудний, але гострий інструмент для цієї задачі: валідуючий, кешуючий резолвер, який можна запускати локально або централізовано, з розумними значеннями за замовчуванням і передбачуваною поведінкою. Ви можете налаштувати його за 15 хвилин. Хитрість — уникнути поширеної пастки: створення петлі з вашим існуючим резолвером (часто systemd-resolved), і витрачання наступної години на роздуми, чому все повертає SERVFAIL.

Чому Unbound (і що ви насправді будуєте)

Unbound — це рекурсивний DNS-резолвер з кешем і опційною DNSSEC-валидацією. «Рекурсивний» означає, що він сам пройде ієрархію DNS (root → TLD → авторитативний), замість того, щоб просити когось іншого це зробити. «Кешуючий» означає, що якщо 5000 процесів запитають один і той самий запис, ви не робитимете 5000 звернень вгору по ланцюгу. А DNSSEC-валидація дозволяє відкидати підроблені відповіді — але це додає складності, якщо ваше середовище неідеальне.

Фактично ви будуєте межу залежностей:

  • Ваші хости залежать від вашого резолвера, а не від того, що DHCP підкинув у кафе минулого року.
  • Ваші застосунки отримують нижчі хвостові затримки при DNS‑інтенсивних workflow (service discovery, CDN, API‑звернення, менеджери пакетів).
  • Ви отримуєте одне місце для спостереження DNS: логи, поведінка кешу, режими відмов.

Класичний продакшн‑патерн виглядає як один із цих варіантів:

  • Локальний кеш на вузлі: Unbound на кожній машині, що слухає на 127.0.0.1, форвардить вгору. Чудово для ноутбуків, окремих серверів або вузлів, чутливих до затримки.
  • Центральний резолвер: Невеликий пул серверів Unbound, клієнти вказують на них. Чудово для флоту, уніфікованої політики й кращої спостережуваності.
  • Гібрид: Локальний Unbound форвардить до центрального Unbound, який виконує рекурсію. Добре, коли хочете локальний кеш плюс централізована політика.

Обирайте свідомо. «Що працює» — це спосіб в кінцевому підсумку отримати петлю резолверів, неконсистентний DNSSEC і кімнату для криз, де всі раптом згадують, що DNS — це важко.

Короткі факти та коротка історія, що має значення

Факти й контекст тут не тривіальні; вони пояснюють, чому існують певні значення за замовчуванням і чому деякі режими відмов повторюються.

  1. DNS старший за веб. RFC для DNS датований початком 1980‑х; він розроблявся для мережі, яка була меншою, дружнішою й менш ворожою.
  2. TTL — це контракт, а не рекомендація. Кешування — очікувана поведінка. Якщо ваш застосунок «потребує» миттєвих DNS‑змін, проблема в застосунку.
  3. Є негативне кешування. NXDOMAIN теж кэшуються, тому одна помилка в імені може переслідувати вас хвилинами.
  4. DNSSEC додали пізніше. Воно додає перевірку цілісності, але також додає більше способів відмови (зсув часу, пошкоджені ланцюги, проблеми з MTU/фрагментацією).
  5. Резолвери — це не просто «сервер». Вони — машини станів: відкриті запити, повторні спроби, таймаути, кеш і політика.
  6. Файл root hints не опціональний для повної рекурсії. Якщо ви робите справжню рекурсію, вам потрібен спосіб знайти root‑сервери. Сучасні пакети це роблять за вас, але концепція важлива.
  7. EDNS0 змінив гру. Більші UDP‑повідомлення і записи DNSSEC зробили відповіді більшими, що вивело на світ пристрої мережі, які не люблять фрагментацію.
  8. systemd-resolved популяризував модель stub‑резолвера. Локальний stub на 127.0.0.53 може бути нормальним — поки ви не нашаруєте його з іншим локальним резолвером і не створюєте петлю.
  9. Unbound походить з екосистеми NLnet Labs. Його роблять люди, що живуть і дихають коректністю DNS; це не хобі‑проект.

Цитата, яку варто тримати в голові, поки робите це:

«Сподівання — це не стратегія.» — Джеймс Кемерон

Робота над надійністю DNS — саме те місце, де ця фраза виправдовує себе. Ви не «сподіваєтеся», що шлях резолвера є адекватним. Ви це доводите.

Налаштування за 15 хвилин: Ubuntu/Debian, безпечно для продакшну

Це налаштування оптимізоване під «отримати стабільний кешуючий резолвер швидко», без підсаджування себе на гачок пізніше. Передбачається наявність systemd (Ubuntu/Debian) і те, що ви згодні, щоб Unbound спочатку слухав тільки localhost. Згодом ви зможете прив’язати його до LAN‑IP для клієнтів.

Крок 1: Встановіть Unbound (та інструменти)

cr0x@server:~$ sudo apt-get update
...output...
cr0x@server:~$ sudo apt-get install -y unbound dnsutils
...output...

Що означає вивід: Ви маєте побачити встановлення Unbound і створення systemd‑юніту. Якщо apt підвантажує щось несподіване (наприклад інший резолвер, про який ви не думали), призупиніться й прочитайте список залежностей.

Рішення: Продовжуйте лише якщо розумієте, що зараз на хості забезпечує DNS (systemd-resolved vs Unbound). Два резолвери можуть співіснувати, але лише якщо ви явно визначите їхні ролі.

Крок 2: Створіть мінімальну, безпечну конфігурацію Unbound

На Debian/Ubuntu головна конфігурація Unbound зазвичай у /etc/unbound/unbound.conf і включає снипети з /etc/unbound/unbound.conf.d/. Ми додамо снипет, щоб оновлення пакета не перезаписали ваші зміни.

cr0x@server:~$ sudo tee /etc/unbound/unbound.conf.d/local-cache.conf >/dev/null <<'EOF'
server:
  # Listen only on localhost to start. Expand later.
  interface: 127.0.0.1
  port: 53

  # Allow local queries only (for now).
  access-control: 127.0.0.0/8 allow

  # Basic hardening and privacy.
  hide-identity: yes
  hide-version: yes
  qname-minimisation: yes

  # Cache tuning: safe defaults.
  cache-min-ttl: 0
  cache-max-ttl: 86400
  cache-max-negative-ttl: 300
  prefetch: yes

  # Reliability.
  do-daemonize: no
  use-syslog: yes
  verbosity: 1

  # DNSSEC validation on (default on many distros, but be explicit).
  auto-trust-anchor-file: "/var/lib/unbound/root.key"

  # Avoid UDP fragmentation pain by advertising a conservative buffer.
  edns-buffer-size: 1232
EOF
...output...

Що означає вивід: Якщо файл відображений назад, він записаний. Якщо бачите «Permission denied», ви забули sudo або неправильно вказали шлях.

Рішення: Тримайте його локальним (localhost) поки не перевірите, що конфіг ідеальний. Відкриття резолвера в мережу без access-control — найкоротший шлях до того, щоб стати відкритим резолвером. Це закінчується погано й голосно.

Крок 3: Запустіть і ввімкніть Unbound

cr0x@server:~$ sudo systemctl enable --now unbound
...output...
cr0x@server:~$ systemctl status unbound --no-pager
● unbound.service - Unbound DNS server
     Loaded: loaded (/lib/systemd/system/unbound.service; enabled; vendor preset: enabled)
     Active: active (running) ...
...output...

Що означає вивід: «active (running)» — це базовий мінімум. Якщо статус «failed», прочитайте останні рядки; Unbound зазвичай відвертий щодо помилок парсингу конфігу.

Рішення: Якщо Unbound не запущено, не чіпайте resolv.conf. Спочатку виправте Unbound. Інакше ви ризикуєте вирізати власне SSH‑з’єднання.

Крок 4: Вкажіть хосту використовувати Unbound (не ламаючи systemd-resolved)

Ось де народжується поширена пастка. На багатьох сучасних системах /etc/resolv.conf є симлинком на stub systemd‑resolved і вказує на 127.0.0.53. Якщо ви наївно налаштуєте Unbound форвардити на «те, що в resolv.conf», ви можете створити петлю: Unbound → stub → Unbound → stub… поки все не почне таймаутитись.

Ми зробимо це акуратно:

  • Опція A (просто): Вимкнути systemd-resolved і дозволити Unbound бути резолвером.
  • Опція B (співіснування): Залишити systemd-resolved, але налаштувати його використовувати 127.0.0.1 (Unbound) як upstream, і переконатися, що Unbound не форвардить назад в stub.

Опція A: Unbound як єдиний локальний резолвер

cr0x@server:~$ sudo systemctl disable --now systemd-resolved
...output...
cr0x@server:~$ sudo rm -f /etc/resolv.conf
...output...
cr0x@server:~$ printf "nameserver 127.0.0.1\noptions edns0 trust-ad\n" | sudo tee /etc/resolv.conf
nameserver 127.0.0.1
options edns0 trust-ad

Що означає вивід: /etc/resolv.conf тепер реальний файл, що вказує на Unbound. Опція trust-ad просить автентифіковані дані (AD bit), коли це можливо.

Рішення: Використовуйте Опцію A на серверах, де хочете менше рухомих частин і контролюєте мережу. Це також простіше для розуміння о 03:00.

Опція B: Залишити systemd-resolved, використовувати Unbound як upstream

Це уникає деяких краєвих випадків з VPN‑клієнтами та split DNS, які залежать від systemd-resolved. Налаштуйте resolved використовувати Unbound:

cr0x@server:~$ sudo mkdir -p /etc/systemd/resolved.conf.d
...output...
cr0x@server:~$ sudo tee /etc/systemd/resolved.conf.d/unbound-upstream.conf >/dev/null <<'EOF'
[Resolve]
DNS=127.0.0.1
Domains=~.
DNSStubListener=yes
EOF
...output...
cr0x@server:~$ sudo systemctl restart systemd-resolved
...output...

Що означає вивід: resolved все ще є stub на 127.0.0.53, але форвардить на Unbound на 127.0.0.1. Це нормально якщо тільки Unbound не форвардить назад.

Рішення: Обирайте Опцію B, коли вам потрібні фічі systemd-resolved (per‑link DNS, інтеграція VPN), але ви хочете кешування/валідацію від Unbound.

Поширена пастка: петлі резолверів (симптоми, докази, виправлення)

Петля зазвичай відбувається так:

  1. Система вказує на stub‑резолвер на 127.0.0.53 (systemd-resolved).
  2. Ви встановлюєте Unbound і ставите його форвардити на «те, що в /etc/resolv.conf».
  3. Unbound форвардить на 127.0.0.53.
  4. systemd-resolved налаштований (явно або через автоматизацію) використовувати 127.0.0.1 (Unbound) або «локальний DNS».
  5. Вітаємо: ви створили DNS‑оуроборос.

Патерн симптомів: короткі сплески успіху, потім таймаути; SERVFAIL; високий CPU в Unbound; логи з повторюваними запитами; dig, що триває ~5 секунд і нічого корисного не повертає.

Доказ: визначте, до кого реально звертається система

cr0x@server:~$ readlink -f /etc/resolv.conf
/run/systemd/resolve/stub-resolv.conf

Що означає вивід: Ви використовуєте stub systemd-resolved, а не Unbound напряму.

Рішення: Якщо ви планували Опцію A, виправте resolv.conf. Якщо ви планували Опцію B, переконайтесь, що Unbound не форвардить на 127.0.0.53.

Доказ: подивіться, куди Unbound форвардить (якщо форвардить)

cr0x@server:~$ sudo unbound-checkconf
unbound-checkconf: no errors in /etc/unbound/unbound.conf

Що означає вивід: Конфіг парсується. Це не означає, що ваш форвардінг правильний; це лише означає, що Unbound може прочитати файл без помилок.

Рішення: Якщо у вас налаштовано forward-zone, переконайтесь, що він вказує на реальні upstream IP (не на ваш локальний stub, якщо тільки ви цього не хочете навмисно).

Виправлення: оберіть напрямок і зробіть його одностороннім

Правила в один бік, які врятують вас від проблем:

  • Якщо Unbound працює рекурсивно, не форвардьте його до systemd-resolved.
  • Якщо Unbound форвардить, форвардьте до відомих upstream IP (корпоративні резолвери або зовнішні резолвери) — не «те, що у resolv.conf».
  • Якщо systemd-resolved форвардить на Unbound, Unbound не повинен форвардити назад на systemd-resolved.

Жарт №1 (короткий, по суті): DNS‑петлі як офісні органіграми: здаються нормальними, доки не помітиш, що всі звітують самі собі.

Перевірка: доведіть, що це кешує й валідуює

DNS — одна з тих систем, де «виглядає нормально» — це пастка. Перевірте:

  • Запити відповідає Unbound (а не минають його).
  • Другий запит швидший (кеш працює).
  • Статус DNSSEC коректний (якщо увімкнено).
  • Затримки й таймаути в межах очікуваного.

Базовий тест запиту

cr0x@server:~$ dig @127.0.0.1 example.com A +noall +answer +stats
example.com.		86396	IN	A	93.184.216.34
;; Query time: 28 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
...output...

Що означає вивід: Рядок SERVER: повинен бути 127.0.0.1 (Unbound). Час запиту в десятках мілісекунд для холодного кешу — нормальний.

Рішення: Якщо сервер не 127.0.0.1, ваші клієнти не використовують Unbound. Виправте конфіг резолвера перед тим, як налаштовувати щось інше.

Доказ кешу: запустіть двічі

cr0x@server:~$ dig @127.0.0.1 example.com A +noall +answer +stats
example.com.		86396	IN	A	93.184.216.34
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
...output...

Що означає вивід: 1–2 ms вказує на попадання в кеш (або принаймні дуже швидкий шлях). Це і є вся суть.

Рішення: Якщо другий запит не швидший, перевірте, чи ви не обходите Unbound або чи кеш ефективно не відключений у конфігурації/політиці.

Сигнал DNSSEC: попросіть AD bit

cr0x@server:~$ dig @127.0.0.1 dnssec-failed.org A +dnssec +noall +comments +answer
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 12345
...output...

Що означає вивід: dnssec-failed.org навмисно неправильно підписаний; валідуючий резолвер має повертати помилку. SERVFAIL тут — хороший знак.

Рішення: Якщо вам потрібна DNSSEC‑валідація для політики/безпеки, зберігайте таку поведінку. Якщо це ламає критичні внутрішні імена (бо внутрішній DNS «креативний»), можливо, доведеться обмежити DNSSEC або форвардити внутрішні зони.

Практичні завдання (команди, що означає вивід, рішення)

Ви попросили реальні завдання. Ось більше десятка. Кожне дає щось операційно дієве.

Завдання 1: Підтвердіть, що Unbound слухає там, де ви думаєте

cr0x@server:~$ sudo ss -lntup | grep -E ':(53)\b'
udp   UNCONN 0      0        127.0.0.1:53        0.0.0.0:*    users:(("unbound",pid=1234,fd=5))
tcp   LISTEN 0      128      127.0.0.1:53        0.0.0.0:*    users:(("unbound",pid=1234,fd=6))

Що означає вивід: UDP і TCP 53 на 127.0.0.1. TCP важливий для великих відповідей і fallback‑поведінки.

Рішення: Якщо бачите 0.0.0.0:53 несподівано, ви могли відкрити резолвер у мережу. Виправте інтерфейси/access-control перед тим, як продовжувати.

Завдання 2: Підтвердіть, який резолвер використовує хост (і чи це симлінк)

cr0x@server:~$ ls -l /etc/resolv.conf
lrwxrwxrwx 1 root root 39 Jan  1 10:00 /etc/resolv.conf -> /run/systemd/resolve/stub-resolv.conf

Що означає вивід: В грі stub systemd-resolved.

Рішення: Вирішіть: відключити resolved (Опція A), або налаштувати його використовувати Unbound upstream (Опція B). Не залипайте посередині.

Завдання 3: Перевірте поточні upstream у systemd-resolved

cr0x@server:~$ resolvectl status
Global
       LLMNR setting: yes
MulticastDNS setting: no
  DNSOverTLS setting: no
      DNSSEC setting: allow-downgrade
    DNSSEC supported: yes
  Current DNS Server: 127.0.0.1
         DNS Servers: 127.0.0.1
...output...

Що означає вивід: resolved форвардить на 127.0.0.1 (Unbound). Це має сенс лише якщо Unbound не форвардить назад у resolved.

Рішення: Якщо Current DNS Server — 127.0.0.53 або якийсь старий DHCP‑сервер, якому ви не довіряєте, виправте конфіг resolved або ваш network manager.

Завдання 4: Перевірте синтаксис конфігу Unbound (швидке запобігання відмов)

cr0x@server:~$ sudo unbound-checkconf /etc/unbound/unbound.conf
unbound-checkconf: no errors in /etc/unbound/unbound.conf

Що означає вивід: Синтаксис в порядку. Якщо він друкує помилку, вона вкаже на потрібний рядок.

Рішення: Ніколи не перезавантажуйте/рестартуйте Unbound у продакшні без кроку unbound-checkconf в автоматизації. Люди помиляються. DNS не пробачає.

Завдання 5: Перевірте живі статистики Unbound (чи він справді обслуговує?)

cr0x@server:~$ sudo unbound-control status
version: 1.17.1
verbosity: 1
threads: 1
modules: 2 [ subnetcache validator iterator ]
uptime: 320 seconds
options: control(ssl)
unbound-control statistics not enabled

Що означає вивід: Контроль працює, але статистики не увімкнені за замовчуванням у деяких збірках.

Рішення: Якщо хочете спостережуваності, увімкніть stats і remote‑control явно (у наступних розділах). Якщо control не працює, виправте права/серти перед тим, як залежати від нього.

Завдання 6: Перевірте логи на предмет петлі резолверів або таймаутів upstream

cr0x@server:~$ sudo journalctl -u unbound -n 50 --no-pager
...output...
unbound[1234]: info: resolving example.com. A IN
unbound[1234]: info: response for example.com. A IN
...output...

Що означає вивід: Ви хочете бачити «resolving» після чого «response». Повторювані «timed out» або «SERVFAIL» — ранній дим.

Рішення: Якщо домінують таймаути, підозрівайте мережевий шлях, фаєрвол або MTU/фрагментацію. Якщо SERVFAIL — підозрюйте DNSSEC або петлю.

Завдання 7: Підтвердіть, що хост використовує Unbound через шлях libc (не тільки dig)

cr0x@server:~$ getent ahosts example.com | head
93.184.216.34   STREAM example.com
93.184.216.34   DGRAM  example.com
93.184.216.34   RAW    example.com

Що означає вивід: Резолвер libc отримує корисну відповідь. Це ловить випадки, коли dig працює, але системний резолвер — ні (несподіванки з NSS/nsswitch, search domains тощо).

Рішення: Якщо getent не працює, а dig працює, швидше за все проблема в NSS/nsswitch або resolv.conf, а не в Unbound.

Завдання 8: Перевірте сигнали попадання в кеш, таймуючи повторні запити

cr0x@server:~$ for i in 1 2 3; do dig @127.0.0.1 www.cloudflare.com A +noall +stats | grep -E 'Query time|SERVER'; done
;; Query time: 24 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)

Що означає вивід: Поведінка холодного → теплого кешу видима. Якщо завжди повільно, ви не кешуєте ефективно.

Рішення: Якщо завжди повільно, перевірте, чи не вимкнено prefetch, чи кеш надто малий, або чи ви форвардите до upstream, що вимикає семантику кешування (рідко, але буває з «розумними» шлюзами).

Завдання 9: Швидко виявляйте відмови, пов’язані з DNSSEC

cr0x@server:~$ dig @127.0.0.1 www.iana.org A +dnssec +noall +comments | head -n 5
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4242
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
...output...

Що означає вивід: Прапорець ad вказує на валідовані дані (коли доступні). Якщо ви ніколи не бачите ad, валідація може не працювати, або клієнт не запитує/не виводить її правильно.

Рішення: Якщо вам потрібна валідація і ви не бачите AD, перевірте trust anchor, синхронізацію часу й чи випадково не вимкнули модуль валідатора.

Завдання 10: Перевірте синхронізацію часу (тиха залежність DNSSEC)

cr0x@server:~$ timedatectl status
Local time: Wed 2025-12-31 10:00:00 UTC
Universal time: Wed 2025-12-31 10:00:00 UTC
RTC time: Wed 2025-12-31 10:00:01
System clock synchronized: yes
NTP service: active
...output...

Що означає вивід: DNSSEC‑валідація може падати, якщо ваш годинник досить неправильно налаштований, щоб підписи виглядали простроченими або ще не дійсними.

Рішення: Якщо годинник не синхронізовано, виправте NTP перед тим, як звинувачувати Unbound або upstream‑резолвери.

Завдання 11: Перевірте правила фаєрволу для DNS (UDP і TCP)

cr0x@server:~$ sudo iptables -S | grep -E 'dport 53|sport 53' || true
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 53 -j ACCEPT

Що означає вивід: Вихідний DNS дозволений. Якщо TCP заблоковано, ви побачите дивні випадкові відмови, коли відповіді не влазять в UDP.

Рішення: Дозвольте TCP/53 вихідний трафік. Його блокування — класична політика «працює, поки не зламається».

Завдання 12: Підтвердіть досяжність upstream (якщо форвардите)

cr0x@server:~$ dig @1.1.1.1 example.com A +time=2 +tries=1 +noall +stats
;; Query time: 18 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
...output...

Що означає вивід: Якщо ваш обраний форвардер повільний/недоступний з цього хоста, Unbound виглядатиме погано, навіть якщо він ні в чому не винен.

Рішення: Обирайте форвардери, які досяжні, низьколатентні та сумісні з політикою (особливо в корпоративних мережах зі split DNS).

Завдання 13: Зловіть петлю резолверів за допомогою спостереження пакетів

cr0x@server:~$ sudo tcpdump -ni lo port 53 -c 10
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:00:01.000000 IP 127.0.0.1.55555 > 127.0.0.1.53: 1234+ A? example.com. (28)
10:00:01.000100 IP 127.0.0.1.53 > 127.0.0.1.55555: 1234* 1/0/0 A 93.184.216.34 (44)
...output...

Що означає вивід: Трафік DNS по loopback існує (добре для локального резолвера). Якщо бачите повторювані запити без відповідей або трафік, що відскакує між 127.0.0.1 і 127.0.0.53 у паттернах, ви побудували петлю.

Рішення: Якщо доказ вказує на петлю, припиніть гадати й виправте ланцюжок. Один резолвер має бути «остання станція».

Завдання 14: Переконайтесь, що файл кореневого trust anchor існує

cr0x@server:~$ sudo ls -l /var/lib/unbound/root.key
-rw-r--r-- 1 root root 1091 Jan  1 10:00 /var/lib/unbound/root.key

Що означає вивід: Файл trust anchor є. Якщо його нема, валідація поводитиметься непередбачувано або падатиме.

Рішення: Якщо відсутній, встановіть пакет, що його надає (часто unbound-anchor або дистро‑специфічні хук‑скрипти) або згенеруйте анкори правильно, потім перезапустіть.

Форвардинг проти повної рекурсії: обирайте усвідомлено

Unbound може виконувати повну рекурсію або форвардити все (або конкретні зони) на upstream‑резолвери. Тут немає моральної чистоти. Є компроміси.

Повна рекурсія: автономія, менше залежностей, більше поверхні

При повній рекурсії Unbound звертається до root‑серверів і спускається вниз. Переваги:

  • Менша залежність від поведінки upstream‑резолверів.
  • Передбачувана політика кешування і валідації.
  • Часто краща стійкість, якщо в одного провайдера upstream проблемний день.

Витрати:

  • Більше різноманітності трафіку (багато авторитативних серверів), що може активувати суворі правила egress.
  • Більша експозиція до проблем з MTU та «DNS блокується, крім корпоративних резолверів» в мережах.
  • Більше відповідальності: ви володієте всім шляхом рекурсії.

Форвардинг: простота, відповідність політиці та корпоративна реальність

Форвардинг поширений в організаціях: Unbound кешує локально, але пропускає промахи на відомий рекурсивний резолвер (внутрішній, ISP, стек безпеки). Це часто правильний вибір, коли:

  • Вам потрібен split‑horizon внутрішній DNS і ви не можете реплікувати зони.
  • Вимагається фільтрація або логування upstream.
  • Egress обмежений лише кількома IP резолверів.

Безпечна конфігурація форвардингу (і як не форвардити собі в обличчя)

Додайте файл з forward zone. Використовуйте явні IP. Не resolv.conf. Не 127.0.0.53.

cr0x@server:~$ sudo tee /etc/unbound/unbound.conf.d/forwarders.conf >/dev/null <<'EOF'
forward-zone:
  name: "."
  forward-addr: 1.1.1.1
  forward-addr: 1.0.0.1
EOF
...output...
cr0x@server:~$ sudo unbound-checkconf
unbound-checkconf: no errors in /etc/unbound/unbound.conf
cr0x@server:~$ sudo systemctl restart unbound
...output...

Рішення: Якщо ви в корпоративній мережі з внутрішніми зонами, ймовірно, ви захочете форвардити до корпоративних резолверів (не до публічних), плюс явний форвардінг для внутрішніх суфіксів за потреби.

Налаштування продуктивності та надійності, які не підставлять вас пізніше

Більшість інсталяцій Unbound не потребують героїчного тонінгу. DNS легкий у порівнянні з базами даних. Помилки приходять від «оптимізації» без моделі і від ставлення до DNS як безстанного сервісу.

Потоки та файлові дескриптори

Якщо ви запускаєте центральний резолвер для багатьох клієнтів, розгляньте кілька потоків і переконайтесь, що ліміти системних ресурсів не жорсткі. На локальному кеші одного хоста одного потоку достатньо.

Типові перевірки:

cr0x@server:~$ systemctl show unbound -p LimitNOFILE
LimitNOFILE=1048576

Рішення: Якщо LimitNOFILE малий (наприклад 1024) на завантаженому резолвері, підніміть його через systemd override. Якщо вже високий — не чіпайте просто тому, що можете.

EDNS buffer size: тиха правка для «випадкових» збоїв

Ми поставили edns-buffer-size: 1232 не просто так: це знижує ризик фрагментації по типовим сучасним шляхам. Це особливо корисно в середовищах з VPN, тунелями або фаєрволами, які некоректно обробляють фрагменти.

Коли це важливо, симптоми дратують: деякі домени працюють, інші таймаутяться, і іноді повтори успішні через TCP. DNSSEC робить це гірше, бо відповіді більші.

Prefetch: корисно при повторюваному трафіку, шкідливо при різноманітних запитах

prefetch: yes означає, що Unbound може освіжити популярні записи до того, як вони експірнуться. Це згладжує хвости затримок для «гарячих» імен. Але якщо резолвер обслуговує величезну кількість «одного разу» імен (трекінг, ad tech), prefetch може створити додаткове навантаження на upstream.

Не думайте занадто багато; вимірюйте. Якщо upstream‑трафік стрибає і у вас немає стабільних «гарячих» наборів, вимкніть prefetch.

Логування: verbosity — це не спостережуваність

Unbound може логувати багато. У продакшні «багато» стає «шум і рахунки». Тримайте рівень низьким за замовчуванням. Коли потрібно детально — піднімайте тимчасово.

Access control: не станьте частиною чийогось ботнету

Якщо ви прив’яжете Unbound до LAN‑IP, правильно налаштуйте access-control. Відкритий рекурсивний резолвер буде використано для ампліфікаційних атак. Ви не хочете, щоб ваш DNS‑сервер потрапив у чужий звіт по інциденту.

Жарт №2 (короткий, по суті): Запуск відкритого резолвера — чудовий спосіб завести нових друзів в інтернеті. На жаль, вони приходять тільки коли їм потрібна пропускна здатність.

Три корпоративні міні-історії (реалістично, анонімізовано)

Інцидент #1: неправильне припущення (фальсифікат «resolv.conf каже правду»)

Середня SaaS компанія хотіла швидших деплойментів. Їх CI‑ранери багато робили DNS: тягнули контейнери, звертались до артефакт‑сторів, викликали внутрішні API. Хтось запропонував «просто встановити Unbound на ранери для кешування». Розумно.

Інженер написав Ansible‑роль, що встановлювала Unbound і створювала конфіг форвардерів, вказуючи резолвер, знайдений у /etc/resolv.conf. Це мало «поважати локальні мережеві налаштування». На папері — чемно. На практиці багато ранерів мали симлінк /etc/resolv.conf на stub systemd‑resolved на 127.0.0.53.

Окремо інша автоматизація встановила systemd-resolved DNS сервер на 127.0.0.1, щоб «використовувати локальний кеш». Ніхто не зв’язав ці зміни, бо вони впали тижнями раніше і належали різним командам.

Інцидент був спочатку тонким. CI‑джоби почали таймаутитись під час «випадкових» кроків: іноді docker pull, іноді curl до внутрішнього API, іноді навіть apt. Декілька перезапусків допомагали. Черга наростала; інженери звинувачували систему збірки.

Те, що нарешті розкрило проблему — захоплення пакетів на loopback, що показало DNS‑запити, які стрибають між 127.0.0.1 і 127.0.0.53 з повторюваними ID. Петля резолверів. Виправлення було нудним: перестати форвардити на основі resolv.conf, налаштувати явні upstream, документувати один підтримуваний ланцюжок резолверів. Після інциденту ввели правило: «resolv.conf не є джерелом істини; це вивід політики».

Інцидент #2: оптимізація, що відбилася назад (агресивне кешування й несподівані відмови)

Компанія мала центральний кластер Unbound. Вони гордилися графіками продуктивності DNS. Одного кварталу вирішили «знизити навантаження на upstream», збільшивши cache-max-ttl і встановивши cache-min-ttl у ненульове значення, щоб записи лишались теплими навіть якщо авторитативні TTL були маленькі.

За кілька днів команда, що робить деплой, провела роутинг IP за DNS у рамках blue/green роллаута. Авторитативний TTL був навмисно малим. Кластер резолверів, що тепер нав’язував більший мінімальний TTL, продовжував віддавати застарілі IP. Трафік ішов на звільнені ноди. Роллаут виглядав як часткова відмова.

Платформна команда казала, що «DNS не має використовуватись для балансування навантаження». Вони частково праві теоретично, але на практиці організація вже так робила, і зміна резолвера тихо змінила сенс TTL. Це не оптимізація — це семантична зміна в критичній залежності.

Виправлення було двоетапним: відкотити cache-min-ttl до 0 і створити список виключень політики лише для доменів, якими вони повністю керують і де можна дозволити застаріння. Також додали перевірку перед зміною: «Чи змінить це поведінку TTL?» Ви б здивувалися, скільки відмов починаються з того, що хтось забув, що DNS — частина контракту.

Інцидент #3: нудна коректна практика, що врятувала день (staging + canary + швидкий відкат)

Фінансова компанія тримала пару Unbound‑резолверів на датацентр, фронтованих anycast у кожному сайті. Їх DNS був навмисно нудний: мінімальні кастомізації, явні форвардери для внутрішніх зон, рекурсія для всього решта, і жорсткий access control.

Одного вівторка мережна команда розгорнула оновлення політики фаєрволу. Воно випадково заблокувало вихідний TCP/53 з VLAN резолверів, залишивши UDP/53 дозволеним. Більшість запитів продовжували працювати. Потім почалися відмови: деякі домени (особливо DNSSEC‑підписані з великими відповідями) почали таймаутитись. Застосунки, що залежали від цих доменів, падали у вигляді «TLS handshake issues» або «випадкові API таймаути».

Ось що їх врятувало: у кожному сайті був canary‑резолвер на окремому політичному шляху, і вони регулярно запускали набір DNS‑перевірок проти нього (включно з примусом TCP DNS запитів). Canary загорівся за кілька хвилин. Вони могли впевнено сказати: «це транспорт DNS, а не застосунок».

Відкат пройшов чисто, бо конфіг Unbound керувався версіоновано, а фаєрвол‑команда мала протестований план відкату. Вплив на сервіс залишився локалізованим. Нікому не дали бейдж героя. Оце і є суть.

Швидкий плейбук діагностики

Коли DNS «повільний» або «впав», часу на філософію немає. Потрібна чітка послідовність, що швидко знаходить вузьке місце.

Перше: підтвердіть, з ким ви спілкуєтесь

  1. Перевірте /etc/resolv.conf і чи це симлінк.
  2. Запустіть dig явно проти Unbound (@127.0.0.1).
  3. Порівняйте dig example.com (за замовчуванням) та dig @127.0.0.1 example.com.

Якщо запити за замовчуванням повільні, але напряму до Unbound швидкі, проблема в шляху системного резолвера (resolved/NSS/VPN), а не в Unbound.

Друге: визначте, чи це upstream, DNSSEC або транспорт

  1. Перевірте логи Unbound на предмет таймаутів і патернів SERVFAIL.
  2. Протестуйте відомі‑хороші домени з +dnssec і шукайте ad або очікуваний SERVFAIL на неправильно підписаних доменах.
  3. Примусіть TCP з +tcp, щоб побачити, чи пов’язана проблема з фрагментацією UDP.

Якщо TCP працює, а UDP падає періодично — підозрюйте MTU/фаєрволи, що ламають фрагментацію. Якщо SERVFAIL переважає на підписаних доменах — підозрюйте DNSSEC/час/trust anchor.

Третє: перевірте ресурсні обмеження та насичення

  1. Перевірте, чи Unbound не завантажує CPU (load, процес CPU) або не обмежений дескрипторами файлів.
  2. Перевірте наявність втрат пакетів і повторних відправок на egress‑інтерфейсі резолвера.
  3. Перевірте показник попадань у кеш через unbound-control stats_noreset (якщо увімкнено).

Якщо у вас немає статистик, увімкніть їх перед наступним інцидентом. «Додамо спостережуваність пізніше» — це шлях у «ніколи».

Поширені помилки: симптоми → корінь → виправлення

1) Симптом: SERVFAIL для більшості запитів, іноді працює при повторі

Корінь: Петля резолверів (Unbound форвардить на systemd stub, який форвардить назад), або таймаути upstream.

Виправлення: Зробіть ланцюжок одностороннім. Використовуйте явні форвардери в Unbound або вимкніть systemd-resolved. Підтвердіть за допомогою readlink -f /etc/resolv.conf і tcpdump -ni lo port 53.

2) Симптом: Деякі домени постійно падають; інші в порядку

Корінь: Помилки DNSSEC, проблеми MTU/фрагментації або блокування TCP/53.

Виправлення: Тестуйте з dig +dnssec і dig +tcp. Встановіть edns-buffer-size: 1232. Дозвольте вихідний TCP/53. Перевірте синхронізацію часу.

3) Симптом: DNS «працює» на хості резолвера, але клієнти не можуть ним користуватись

Корінь: Unbound прив’язаний лише до 127.0.0.1; відсутні access-control для підмереж клієнтів; фаєрвол блокує вхідний 53.

Виправлення: Додайте interface: 0.0.0.0 або конкретний LAN IP, додайте access-control: 10.0.0.0/8 allow (або вашу підмережу) і дозвольте вхідні UDP/TCP 53 на інтерфейсі.

4) Симптом: Високі сплески латентності кожні кілька хвилин

Корінь: Кеш занадто малий, поведінка prefetch спричиняє бум, upstream‑резолвери лімітують, або втрата пакетів.

Виправлення: Увімкніть статистики та подивіться на попадання кешу. Якщо форвардите, протестуйте latency upstream напряму. Розгляньте вимкнення prefetch, якщо набір запитів дуже різноманітний.

5) Симптом: Внутрішні домени падають, публічні працюють

Корінь: Ви обрали повну рекурсію, але внутрішні зони доступні лише через корпоративні резолвери (split‑horizon). Або ви форвардите «.» до публічних резолверів, які не бачать внутрішніх імен.

Виправлення: Додайте per‑zone форвардинги для внутрішніх суфіксів до корпоративних DNS‑серверів. Залишайте рекурсію або форвардинг для решти за потреби.

6) Симптом: Все ламається після ввімкнення DNSSEC‑валідації

Корінь: Зсув часу, відсутній trust anchor або пошкоджена DNSSEC‑ланцюжок upstream (поширено з деякими middlebox і старими форвардерами).

Виправлення: Виправте NTP/час. Перевірте /var/lib/unbound/root.key. Якщо форвардите до upstream, що ламає DNSSEC, або змініть upstream, або відключіть валідацію для певних внутрішніх зон замість вимикання глобально.

7) Симптом: Випадкові NXDOMAIN для імен, що мають існувати

Корінь: Неправильна обробка search domain, плутанина зі split DNS або негативне кешування після тимчасового upstream‑збоju.

Виправлення: Перевірте search domains і спробуйте повністю‑кваліфіковані імена з крапкою в кінці в dig. Розгляньте зниження cache-max-negative-ttl, якщо транзиторні NXDOMAIN трапляються часто (але не ставте його в нуль, якщо не любите навантаження upstream).

Чеклісти / покроковий план

План A: Локальний кешуючий резолвер на одному сервері (15‑хвилинна версія)

  1. Встановіть unbound і dnsutils.
  2. Налаштуйте Unbound слухати лише на 127.0.0.1.
  3. Увімкніть DNSSEC, встановіть edns-buffer-size: 1232.
  4. Запустіть Unbound і підтвердіть, що він слухає на 127.0.0.1:53 (UDP+TCP).
  5. Виберіть: вимкнути systemd-resolved (простішe) або налаштувати його форвардити на Unbound.
  6. Перевірте за допомогою dig @127.0.0.1 і getent.
  7. Запустіть перевірку на петлю: переконайтесь, що Unbound не форвардить на 127.0.0.53.

План B: Центральний резолвер для підмережі (якщо хочете, щоб інші машини ним користувались)

  1. Прив’яжіть Unbound до LAN IP (не 0.0.0.0, якщо лише не маєте наміру).
  2. Додайте access-control записи для підмереж клієнтів.
  3. Фаєрвол: дозвольте вхідні UDP/TCP 53 з цих підмереж; дозвольте вихідні UDP/TCP 53 до upstream або в інтернет (якщо рекурсія).
  4. Вирішіть рекурсія vs форвардинг; налаштуйте явні форвардери за потреби.
  5. Canary‑тест з клієнта: dig @resolver-ip example.com.
  6. Додайте другий резолвер для надлишковості; вказуйте клієнтам обидва.
  7. Інструментуйте: увімкніть Unbound stats; переконайтесь, що логи адекватні й обмежені за швидкістю.

План C: Управління змінами, що запобігає інцидентам DNS

  1. Зробіть ланцюжок резолверів явним у документації: client → stub (опційно) → Unbound → upstream.
  2. Додайте валідацію конфігу до деплойменту (unbound-checkconf має проходити).
  3. Canary‑запити: включіть тест DNSSEC та примусовий TCP‑запит.
  4. Майте план відкату: повернути конфіг, перезапустити, підтвердити слухання і успішність запитів.

Питання й відповіді

1) Чи запускати Unbound на кожному хості чи централізовано?

Якщо хочете простішу історію надійності для флоту, запускайте невеликий центральний пул і вказуйте клієнтів на нього. Якщо потрібна найкраща локальна latency і стійкість до мережевих коливань, запускайте локально. Гібрид — теж варіант, якщо задокументувати ланцюжок і уникати петель.

2) Чи кращий Unbound за systemd-resolved?

Вони вирішують різні задачі. systemd-resolved — це stub‑резолвер з per‑link логікою; Unbound — повноцінний рекурсивний кешуючий резолвер. Використовуйте resolved для мережевого водопостачання, Unbound — для політики/кешу/валідації DNS. Просто не дозволяйте їм бігати один за одним у коло.

3) Чи потрібна мені DNSSEC‑валідація?

Якщо ви можете тримати синхронізацію часу солідною і ваша мережа не руйнує DNS, валідація — гарний захисний шар. Якщо середовище має ненадійні middlebox або зламаний внутрішній DNSSEC, застосовуйте її обережно або сегментуйте, інакше ви обміняєте безпеку на відмови.

4) Чому потрібен TCP/53, якщо DNS — «UDP»?

Тому що великі відповіді існують (DNSSEC, великі TXT, великі набори NS), і усічення відповіді призводить до TCP‑fallback. Блокування TCP/53 створює періодичні, специфічні для домену відмови, які виглядають як примари.

5) Який найбезпечніший спосіб конфігурувати форвардери?

Використовуйте явні IP у forward-zone. Не «форвардьте в resolv.conf». resolv.conf часто є stub, і stubs — це шлях до петель.

6) Чи може Unbound виконувати авторитативний DNS?

Він може робити певні local‑data, але це не авторитативний DNS у сенсі NSD або BIND в авторитативному режимі. Використовуйте його переважно як резолвер і тримайте авторитативний DNS окремо, якщо тільки ви не робите маленький, навмисний хак (наприклад, перевизначення кількох імен).

7) Як дізнатись, що кеш справді працює?

Запустіть той самий dig запит двічі проти Unbound і порівняйте Query time. Для глибшого доказу увімкніть статистики і дивіться метрики попадань у кеш. Також перевірте, що клієнти справді відправляють запити в Unbound, а не обходять його.

8) Який добрий TTL для негативного кешування?

П’ять хвилин (cache-max-negative-ttl: 300) — прагматичний дефолт. Знизьте, якщо транзиторний NXDOMAIN вам шкодить. Більші значення можуть затримувати помилки і тимчасові upstream‑помилки довше, ніж хотілося б.

9) Я ввімкнув Unbound, але VPN split DNS перестав працювати. Чому?

Багато VPN‑клієнтів інтегруються з systemd-resolved, щоб встановлювати per‑domain або per‑interface DNS маршрути. Якщо ви вимкнули resolved (Опція A), ви можете втратити цю поведінку. Використайте Опцію B (resolved stub + Unbound upstream) або керуйте split DNS явно в Unbound через forward‑зони.

10) Як уникнути ставати відкритим резолвером?

Прив’язуйте лише до потрібних інтерфейсів і ставте access-control так, щоб дозволяти лише ваші клієнтські мережі. Не виставляйте його в публічний інтернет. Також перевірте через ss, що ви не слухаєте на 0.0.0.0, якщо це не явно потрібно.

Наступні кроки, які варто зробити

Ви можете швидко запустити Unbound. А от запустити його правильно — це те, що збереже вам купу проблем у майбутньому.

  • Зафіксуйте ланцюжок резолверів: вирішіть, чи systemd-resolved у шляху, і зробіть його одностороннім. Жодних петель.
  • Перевірте доказами: dig @127.0.0.1 двічі для кешу, +dnssec для валідації, +tcp для перевірки транспорту.
  • Оберіть рекурсію чи форвардинг усвідомлено: корпоративні мережі зазвичай хочуть форвардинг (принаймні для внутрішніх зон).
  • Додайте canary‑перевірку: один DNSSEC‑тест, один примусовий TCP‑тест, одне внутрішнє ім’я. Запускайте їх постійно.
  • Тримайте конфіг нудним: уникайте хитрих перевизначень TTL і «оптимізуйте» лише після вимірювання.

DNS — це залежність, від якої не сховаєшся. Хороша новина: її можна зробити передбачуваною. Unbound — один із небагатьох інструментів у цій сфері, який поводиться так, ніби хоче, щоб ви спали спокійно.

← Попередня
Контрольний список безпеки Proxmox: 2FA, RBAC, брандмауер, оновлення та безпечний віддалений доступ
Наступна →
Ubuntu 24.04: DNS-кеші брешуть — очищуйте правильний кеш (і припиніть очищати не той) (випадок №26)

Залишити коментар