Свой DNS-резолвер: зачем, какой выбрать и как настроить Unbound за 10 минут.
Каждый раз когда ваш сервер обновляет пакеты, проверяет сертификат, коннектится к внешнему API или отправляет метрики в мониторинг — он резолвит домен. И этот запрос уходит на 1.1.1.1 или 8.8.8.8. Cloudflare видит что ваш сервер в 3 ночи полез на репозиторий пакетов, потом на API платёжной системы, потом на базу данных угроз. Полная картина вашей инфраструктуры — без взлома, просто из DNS-логов.
Свой резолвер решает это. Запросы обрабатываются локально, кэшируются на сервере, а наружу уходит только то что не нашлось в кэше — и то зашифрованным.
ЗАЧЕМ СВОЙ РЕЗОЛВЕР
Приватность — самая очевидная причина. Внешний DNS-провайдер видит каждый домен к которому обращается сервер. Это не паранойя — это реальные данные которые собираются, анализируются и могут утекать. Свой резолвер оставляет эту информацию у вас.
Независимость — менее очевидная но более критичная. 1.1.1.1 надёжный, но это чужой сервер. В октябре 2021 упали DNS серверы Facebook — и всё что зависело от них перестало работать. 1.1.1.1 в тот день работал, но завтра может не повезти именно вашему провайдеру. Свой резолвер ходит напрямую к корневым серверам и не зависит ни от кого.
Как это работает: корневые серверы — это вершина DNS-иерархии. Их 13 групп, они всегда доступны и знают где искать любой домен. Обычный резолвер типа 1.1.1.1 сам ходит к ним и кэширует ответы — вы пользуетесь его кэшем. Свой резолвер делает то же самое, но для вас лично — и ни от чьего кэша не зависит.
Скорость — приятный бонус. Часто запрашиваемые домены оседают в локальном кэше. npm registry, GitHub, Docker Hub — всё это резолвируется за единицы миллисекунд без выхода в интернет.
Контроль — то что открывает новые возможности. Хотите заблокировать конкретный домен на уровне DNS? Добавить внутренние записи для локальной сети? Логировать все DNS-запросы сервера для аудита? Со своим резолвером это делается в конфиге.
Блокировка доменов через local-zone — одна из самых простых и полезных возможностей. Добавьте в конфиг:
server:
# Заблокировать домен — вернуть REFUSED
local-zone: "example.com" refuse
# Заблокировать рекламные сети
local-zone: "doubleclick.net" refuse
local-zone: "googlesyndication.com" refuse
# Перенаправить на свой IP (для внутренних сервисов)
local-zone: "internal.example.com" static
local-data: "internal.example.com A 10.0.0.5"
refuse — резолвер вернёт REFUSED, браузер покажет ошибку DNS. static с local-data — вернёт указанный IP вместо реального. Это удобно для внутренних сервисов которые должны резолвиться в приватный IP.
ТРИ ВАРИАНТА: UNBOUND, BIND, POWERDNS
Выбор резолвера зависит от задачи. Все три решают разные проблемы.
Unbound — специализированный кэширующий резолвер. Не пытается делать всё сразу: он принимает запросы, ищет ответы у корневых серверов, кэширует результат, проверяет DNSSEC. Настраивается за 10 минут, потребление памяти зависит от размера кэша — при конфигурации в этой статье около 150-200 МБ, работает стабильно годами без вмешательства. Если нужен локальный резолвер для сервера или небольшой сети — это правильный выбор.
Bind (named) — промышленный стандарт существующий с 1980-х. Стоит за большей частью DNS-инфраструктуры в мире. Умеет быть одновременно кэширующим резолвером и авторитетным сервером для ваших доменов. Поддерживает GeoDNS — разные ответы для пользователей из разных стран. Умеет split-horizon — разные ответы для внутренней и внешней сети. Мощный инструмент с соответствующей кривой обучения.
PowerDNS — современный вариант для тех кто хочет управлять DNS программно. Зоны хранятся в MySQL или PostgreSQL, записи управляются через REST API. Можно написать скрипт который автоматически создаёт DNS-записи при запуске нового сервера. Выбор для автоматизированных систем и тех кто не хочет редактировать текстовые файлы руками.
Для локального резолвера на одном сервере — Unbound. Для полноценного DNS-сервера с зонами — Bind. Для динамического управления через API — PowerDNS.
UNBOUND: УСТАНОВКА И НАСТРОЙКА
Установка занимает одну команду:
apt install unbound # Debian/Ubuntu
dnf install unbound # RHEL/Fedora
После установки Unbound слушает на 127.0.0.1:53 и готов принимать запросы. Но базовая конфигурация требует нескольких правок.
Откройте конфигурационный файл:
nano /etc/unbound/unbound.conf
Минимальная рабочая конфигурация:
server:
# Слушаем только на localhost
interface: 127.0.0.1
port: 53
# Разрешаем запросы только с локального хоста
access-control: 127.0.0.1/32 allow
access-control: 0.0.0.0/0 refuse
# DNSSEC
auto-trust-anchor-file: "/var/lib/unbound/root.key"
# Скрываем версию и идентификатор
hide-version: yes
hide-identity: yes
# Кэш
cache-min-ttl: 300
cache-max-ttl: 86400
msg-cache-size: 50m
rrset-cache-size: 100m
# Производительность
num-threads: 2
so-reuseport: yes
# Логирование
verbosity: 1
log-queries: no
Скачайте корневые якоря DNSSEC:
unbound-anchor -a /var/lib/unbound/root.key
Проверьте конфигурацию и запустите:
unbound-checkconf
systemctl enable --now unbound
Проверка что работает:
dig @127.0.0.1 cloudflare.com
dig @127.0.0.1 cloudflare.com +dnssec
Второй запрос с +dnssec должен вернуть записи с флагом ad (authenticated data) — значит DNSSEC проверка прошла.
ПОДКЛЮЧЕНИЕ К СИСТЕМНОМУ РЕЗОЛВЕРУ
Unbound запущен, но сервер его ещё не использует — systemd-resolved по-прежнему отправляет запросы на 1.1.1.1. Нужно переключить системный DNS на 127.0.0.1.
Важный момент: DNSSEC и DoT в systemd-resolved нужно отключить. Если оставить их включёнными — systemd-resolved будет пытаться сам валидировать DNSSEC и шифровать запросы поверх того что уже делает Unbound. Двойная работа, и хуже — конфликт настроек. Unbound сам занимается всем этим, systemd-resolved здесь просто передатчик.
# /etc/systemd/resolved.conf
[Resolve]
DNS=127.0.0.1
DNSOverTLS=no
DNSSEC=no
systemctl restart systemd-resolved
resolvectl status | grep "Current DNS Server"
Должно показать 127.0.0.1. Если видите 1.1.1.1 или Hetzner IP — что-то пошло не так, проверьте netplan или /etc/resolv.conf.
Проверка что резолвинг идёт через Unbound:
resolvectl query cloudflare.com
DOT UPSTREAM: ШИФРУЕМ ИСХОДЯЩИЕ ЗАПРОСЫ
Локальный резолвер решает проблему внутри сервера — запросы не уходят на чужой резолвер. Но когда Unbound не находит ответ в кэше, он всё равно идёт к внешним серверам — форвардерам. Этот исходящий трафик по умолчанию идёт открытым текстом по UDP на порт 53. То есть провайдер по-прежнему видит какие домены резолвирует ваш сервер — просто теперь не постоянно, а только при промахе кэша.
DoT upstream шифрует именно эти исходящие запросы. Провайдер видит зашифрованный трафик на порт 853 — но не видит какие домены вы резолвируете.
Добавьте в конфигурацию:
forward-zone:
name: "."
forward-tls-upstream: yes
forward-addr: 1.1.1.1@853#cloudflare-dns.com
forward-addr: 8.8.8.8@853#dns.google
forward-addr: 9.9.9.9@853#dns.quad9.net
Перезапустите:
systemctl restart unbound
Теперь Unbound кэширует локально, а запросы которые не нашлись в кэше шифрует через DoT и передаёт на форвардеры — 1.1.1.1, 8.8.8.8 или 9.9.9.9. Провайдер видит только зашифрованный трафик на порт 853.
ПРОВЕРКА И ОТЛАДКА
Статистика кэша:
unbound-control stats_noreset | grep -E "total|cache"
Сколько запросов обработано и какой процент из кэша — покажет насколько эффективно работает резолвер.
Тест DNSSEC:
# Этот домен должен вернуть SERVFAIL — он намеренно сломан для тестов
dig @127.0.0.1 dnssec-failed.org
# Этот должен резолвиться нормально
dig @127.0.0.1 cloudflare.com +dnssec
Если dnssec-failed.org возвращает SERVFAIL — DNSSEC валидация работает правильно.
Логи:
journalctl -u unbound -f
ИСПОЛЬЗОВАНИЕ СВОЕГО РЕЗОЛВЕРА С ДОМАШНЕГО КОМПА
Unbound в базовой конфигурации слушает только на 127.0.0.1 — доступен исключительно с самого сервера. Но его можно безопасно открыть для конкретного IP — например вашего домашнего компа. Тогда в настройках сети на компе вместо 8.8.8.8 прописываете IP своего сервера, и весь DNS-трафик идёт через ваш резолвер.
Узнайте свой домашний IP:
curl ifconfig.me
Откройте Unbound для этого IP — добавьте в конфиг:
server:
interface: 0.0.0.0
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.1/32 allow
access-control: ВАШ_ДОМАШНИЙ_IP/32 allow
Откройте порт 53 в nftables только для вашего IP — никак иначе:
ip saddr ВАШ_ДОМАШНИЙ_IP udp dport 53 accept
ip saddr ВАШ_ДОМАШНИЙ_IP tcp dport 53 accept
Перезапустите Unbound:
systemctl restart unbound
Проверьте с домашнего компа что резолвер отвечает:
dig @IP_ВАШЕГО_СЕРВЕРА cloudflare.com
Если ответил — прописывайте IP сервера в настройках DNS сетевого адаптера на компе.
Важно: домашний IP обычно динамический — меняется при переподключении. Если IP изменился, резолвер перестанет отвечать. Придётся обновить правило в nftables и конфиг Unbound. Для постоянного использования лучше получить статический IP у провайдера или использовать Dynamic DNS.
КОГДА НУЖЕН BIND ИЛИ POWERDNS
Unbound — резолвер. Он не умеет быть авторитетным сервером для ваших доменов, не поддерживает зоны, не делает GeoDNS.
Если нужно размещать собственные DNS-зоны, настраивать split-horizon DNS, делать GeoDNS с разными ответами для разных стран, или строить полноценную DNS-инфраструктуру — это задача для Bind. Bind умеет быть одновременно и резолвером и авторитетным сервером, поддерживает сложные ACL и view-конфигурации для разделения внутренних и внешних зон.
PowerDNS выбирают когда DNS нужно администрировать программно: зоны хранятся в базе данных, записи управляются через REST API, можно написать собственный backend. Это выбор для автоматизированных систем и облачных провайдеров.
Детальная настройка Bind с практическими примерами — зоны, GeoDNS, split-horizon — разбирается в курсе по настройке DNS-сервера: два урока с полным погружением от базовой конфигурации до продвинутых возможностей.
ИТОГ
Свой резолвер — это не rocket science. Unbound ставится за пять минут, требует 150-200 МБ RAM при стандартной конфигурации кэша, и сразу даёт приватность, независимость от внешних провайдеров и локальное кэширование.
Для большинства серверов этого достаточно. Если задачи растут до уровня собственных зон и сложной маршрутизации DNS-трафика — следующий шаг это Bind.
