MAATRIX / Блог / Unbound на Ubuntu 24.04: пошаговая установка

Unbound на Ubuntu 24.04: пошаговая установка

MAATRIX

Публичные DNS-серверы вроде 8.8.8.8 или 1.1.1.1 удобны, но каждый ваш запрос при этом виден третьей стороне, а ответ можно подделать на пути, если резолвер не проверяет DNSSEC-подписи. Unbound закрывает обе проблемы: он сам ходит к корневым серверам и авторитативным DNS доменов, кэширует ответы локально и проверяет их криптографическую подлинность. Ниже — рабочая установка на чистом VPS с Ubuntu 24.04, без магии и с объяснением, зачем нужен каждый параметр.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое Unbound и зачем он нужен

Unbound — это рекурсивный DNS-резолвер с открытым исходным кодом от NLnet Labs, тот же коллектив, что делает NSD и ldns. В отличие от forwarding-резолвера, который просто пересылает запросы вышестоящему DNS (тому же 8.8.8.8), Unbound делает полную рекурсию сам: сначала идёт к корневым серверам, узнаёт у них сервер зоны .com, затем — сервер конкретного домена, и так до получения ответа. Это медленнее при холодном кэше, зато полностью убирает зависимость от чужого резолвера и его политики логирования.

Второй важный момент — DNSSEC. Unbound из коробки умеет проверять цепочку подписей от корневой зоны до конкретной записи и отбрасывать ответ, если подпись не сходится (типичный признак DNS-спуфинга или атаки на пути). Именно поэтому Unbound часто ставят не как самостоятельное решение, а как бэкенд-резолвер для Pi-hole или AdGuard Home: блокировщик рекламы фильтрует домены по спискам, а Unbound за его спиной честно резолвит то, что осталось, без посредников и с проверкой подписей.

Типичные сценарии на VPS: личный резолвер для WireGuard-клиентов, DNS-бэкенд для Pi-hole/AdGuard, или просто безопасный резолвер для самого сервера вместо systemd-resolved с публичным DNS в качестве апстрима.

Установка и подготовка root hints

Ставим пакет и сразу проверяем версию — в репозиториях Ubuntu 24.04 (noble) идёт Unbound 1.19.x:

sudo apt update
sudo apt install -y unbound unbound-anchor dns-root-data dnsutils
unbound -V | head -n1

Пакет dns-root-data даёт актуальный файл подсказок корневых серверов (root.hints) и обновляет его вместе с системой — не придётся вручную тянуть named.cache с internic.net и следить за его свежестью. Проверяем, что файл на месте:

ls -l /usr/share/dns/root.hints

Теперь нужен доверенный якорь DNSSEC — публичный ключ корневой зоны, от которого строится вся цепочка проверки подписей. unbound-anchor подтягивает его и проверяет через встроенный сертификат IANA:

sudo unbound-anchor -a /var/lib/unbound/root.key
sudo chown unbound:unbound /var/lib/unbound/root.key

Команда либо молча завершится (ключ уже актуален), либо обновит файл. Это нормально запускать и вручную раз в несколько лет — ключ подписи корневой зоны меняется редко, последний раз ротация была в 2018 году, но проверять его целостность стоит.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Освобождаем порт 53 от systemd-resolved

Грабля, в которую упирается почти каждый на свежей Ubuntu: порт 53 на 127.0.0.53 уже занят systemd-resolved. Если планируете, чтобы Unbound слушал 127.0.0.1:53 (не только 127.0.0.1:5335 для Pi-hole), нужно отключить встроенный DNS-стаб:

sudo sed -i 's/^#\?DNSStubListener=.*/DNSStubListener=no/' /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved
sudo rm -f /etc/resolv.conf
sudo ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

После этого resolv.conf будет указывать на реальный upstream (обычно DHCP-выданный DNS), а не на локальный заглушку — временно, пока не переключите систему на Unbound явно через resolvectl. Если Unbound будет работать только как бэкенд для Pi-hole на порту 5335, этот шаг можно пропустить — конфликта портов не будет.

Конфигурация unbound.conf с DNSSEC

Основной конфиг лежит в /etc/unbound/unbound.conf.d/. Не трогаем системный unbound.conf, а создаём отдельный файл — так апдейты пакета не затрут вашу настройку:

sudo nano /etc/unbound/unbound.conf.d/main.conf

Минимальный рабочий вариант для резолвера, слушающего только локальный сервер и подсети WireGuard/LAN:

server:
    interface: 127.0.0.1
    interface: 10.8.0.1
    port: 53

    access-control: 127.0.0.0/8 allow
    access-control: 10.8.0.0/24 allow
    access-control: 0.0.0.0/0 refuse

    do-ip4: yes
    do-ip6: no
    do-udp: yes
    do-tcp: yes

    root-hints: "/usr/share/dns/root.hints"
    auto-trust-anchor-file: "/var/lib/unbound/root.key"

    harden-dnssec-stripped: yes
    harden-glue: yes
    harden-below-nxdomain: yes
    use-caps-for-id: yes

    edns-buffer-size: 1232
    prefetch: yes
    cache-min-ttl: 300
    cache-max-ttl: 86400
    serve-expired: yes

    private-address: 10.0.0.0/8
    private-address: 172.16.0.0/12
    private-address: 192.168.0.0/16
    private-address: fd00::/8

    logfile: "/var/log/unbound/unbound.log"
    verbosity: 1

Ключевые строки: harden-dnssec-stripped: yes заставляет Unbound отбрасывать ответ, если атакующий на пути попытался убрать DNSSEC-подпись целиком (частая техника обхода наивных резолверов), а use-caps-for-id: yes включает рандомизацию регистра букв в запросах — дополнительная защита от подмены ответов. access-control явно ограничивает, кто может слать запросы — без этого правила по умолчанию Unbound слушает только localhost, но при добавлении внешних интерфейсов легко случайно поднять открытый резолвер, который потом используют для DNS-амплификации в DDoS.

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

sudo unbound-checkconf
sudo systemctl enable --now unbound
sudo systemctl status unbound --no-pager

Проверка DNSSEC и логов

Первая проверка — что резолвинг вообще работает:

dig ubuntu.com @127.0.0.1

Дальше — собственно DNSSEC. NLnet Labs держит два тестовых домена именно для этой цели: один с корректной подписью, второй — с намеренно битой:

dig sigok.verteiltesysteme.net @127.0.0.1 +dnssec
dig sigfail.verteiltesysteme.net @127.0.0.1 +dnssec

Первый запрос должен вернуть ответ с флагом ad (authenticated data) в секции flags — это признак того, что Unbound проверил подпись и доверяет ответу. Второй запрос обязан завершиться SERVFAIL — если вместо этого пришёл IP-адрес, DNSSEC-валидация не работает, и стоит перепроверить auto-trust-anchor-file и права на /var/lib/unbound/root.key.

Логи при verbosity: 1 покажут ошибки валидации и таймауты апстримов:

sudo journalctl -u unbound -f

Для более подробной диагностики временно поднимите verbosity: 3 в конфиге, перезапустите сервис, воспроизведите проблему и верните значение обратно — на «тройке» Unbound пишет очень много и быстро заполняет диск на нагруженном сервере.

Интеграция с Pi-hole или AdGuard Home

Самый частый сценарий — Unbound как upstream-резолвер для блокировщика рекламы. В этом случае Unbound слушает не 53-й, а служебный порт 5335 только на loopback, а сам блокировщик остаётся единственным, кто слушает 53-й на всех интерфейсах.

Меняем main.conf:

server:
    interface: 127.0.0.1
    port: 5335
    access-control: 127.0.0.1/32 allow
    access-control: 0.0.0.0/0 refuse
    do-ip4: yes
    do-ip6: no
    root-hints: "/usr/share/dns/root.hints"
    auto-trust-anchor-file: "/var/lib/unbound/root.key"
    harden-dnssec-stripped: yes
    prefetch: yes

После перезапуска Unbound проверяем резолвинг на новом порту:

dig ubuntu.com @127.0.0.1 -p 5335

Дальше в веб-интерфейсе Pi-hole (Settings → DNS) отключаем все публичные апстримы и в поле Custom DNS указываем 127.0.0.1#5335. В AdGuard Home то же самое делается в разделе Upstream DNS servers строкой [/]127.0.0.1:5335. Подробный разбор самой установки блокировщика — в статьях про Pi-hole и AdGuard Home на Ubuntu 24.04.

Firewall и ограничение доступа

DNS-резолвер, открытый в интернет без ограничений, — классический вектор для DNS-амплификации: атакующий подделывает исходный IP жертвы и заваливает её вашими ответами, которые в разы больше запроса. Даже с правильным access-control в конфиге Unbound стоит закрыть порт firewall'ом как второй рубеж:

sudo ufw default deny incoming
sudo ufw allow from 10.8.0.0/24 to any port 53 proto udp
sudo ufw allow from 10.8.0.0/24 to any port 53 proto tcp
sudo ufw allow ssh
sudo ufw enable

Если Unbound работает только на 127.0.0.1 или 127.0.0.1:5335 как бэкенд для Pi-hole/AdGuard, отдельные правила для DNS вообще не нужны — трафик наружу не выходит. Подробнее про настройку самого фаервола — в статье про UFW на Ubuntu 24.04. Держите систему в курсе обновлений: unattended-upgrades для пакета unbound закрывает известные CVE без ручного вмешательства, а сам Unbound стоит перечитывать на предмет новых версий раз в несколько месяцев.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Unbound работает медленнее, чем 1.1.1.1, — это нормально?

Да, при холодном кэше и полной рекурсии первый запрос к новому домену будет заметно медленнее, чем к forwarding-резолверу с прогретым кэшем миллионов пользователей. После прогрева (prefetch: yes помогает обновлять записи до истечения TTL) разница обычно не критична для повседневного использования.

Можно ли использовать Unbound вместе с DoH или DoT?

Сам Unbound умеет выступать сервером DoT (tls-service-key/tls-service-pem), но как клиент к вышестоящим серверам обычно используется в режиме прямой рекурсии — без апстрима вообще. Если нужен именно DNS поверх HTTPS для доступа к заблокированным сервисам, это отдельная задача, разобранная в статье про DNS over HTTPS.

Что делать, если после установки dig пишет connection refused?

Проверьте, что Unbound реально слушает нужный интерфейс: sudo ss -lunp | grep unbound. Частая причина — конфиг не прошёл проверку unbound-checkconf из-за опечатки, и сервис не поднялся, хотя systemctl status может показывать «active» для самого юнита при определённых ошибках.

Нужен ли root.hints, если у меня уже есть auto-trust-anchor-file?

Да, это разные вещи: root-hints — список IP корневых серверов для старта рекурсии, auto-trust-anchor-file — криптографический ключ для проверки подписей. Одно без другого не даст ни резолвинга (без hints), ни DNSSEC-валидации (без ключа).

Как понять, что DNS-запросы действительно не утекают к провайдеру или третьим DNS?

Если Unbound работает поверх VPN-туннеля на сервере, полезно дополнительно проверить отсутствие утечек с клиента — методика описана в статье про проверку и закрытие DNS-утечек через VPN.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →