Когда в инфраструктуре появляется два-три сервера, можно ещё обходиться файлом /etc/hosts. Когда их становится десятки, а потом сотни, ручная правка превращается в каторгу, а опечатка в IP-адресе ломает половину сервисов. Именно тут на сцену выходит DNS - тихая опора всей сетевой коммуникации, без которой не работает ни один современный кластер. Среди серверного программного обеспечения для разворачивания собственного DNS пальма первенства уже несколько десятилетий держится за BIND, и причины этого кроются не в моде, а в проверенной временем надёжности.
BIND расшифровывается как Berkeley Internet Name Domain, и это свободное программное обеспечение с открытым исходным кодом. По разным оценкам, более 70% всех DNS-серверов в интернете работают именно на нём. Корни проекта уходят в 1980-е годы, и за это время продукт оброс таким количеством возможностей, что назвать его просто DNS-сервером язык не поворачивается. BIND умеет работать как авторитативный сервер, как кеширующий резолвер, поддерживает балансировку нагрузки, динамические обновления, разделённый DNS, DNSSEC, IPv6 и многое другое.
Если речь идёт о Unix-подобных системах, BIND остаётся одним из самых стабильных вариантов. Пакеты доступны практически в каждом дистрибутиве Linux, а в комплекте идут полезные утилиты для диагностики и проверки. Ниже подробно разобран процесс установки и настройки BIND9 на Ubuntu 22.04 в схеме с двумя серверами - первичным (мастер) и вторичным (slave). Такая конфигурация даёт отказоустойчивость и снимает нагрузку с одного узла.
Подготовительные требования к окружению и список того, что должно быть под рукой перед стартом
Прежде чем переходить к установке пакетов, нужно убедиться, что в наличии есть базовый набор. Понадобятся два сервера на Ubuntu 22.04 - один станет мастером, второй вторичным. Доступ к каждому серверу должен быть с правами обычного пользователя, у которого есть возможность повышать привилегии через sudo. Использование чистого root-пользователя для повседневных задач считается дурным тоном, и лучше от этой практики отказаться сразу.
Сетевая связность между серверами должна работать стабильно - оба узла обязаны видеть друг друга по IP. Желательно проверить ping, а ещё лучше пробежаться по портам через telnet или nc до начала настройки. Если между серверами стоит файрвол, придётся открыть UDP/TCP порт 53, иначе передача зон попросту не состоится.
Корректная настройка полного доменного имени для каждого узла перед установкой пакетов
FQDN или Fully Qualified Domain Name - это полное доменное имя сервера, по которому его можно однозначно идентифицировать в сети. Без правильно выставленного FQDN BIND будет ругаться при старте, а часть утилит начнёт выдавать невнятные предупреждения. Поэтому первым делом нужно привести в порядок имена обоих серверов.
В рамках этого руководства используются следующие параметры:
Hostname IP Address FQDN Used As
---------------------------------------------------------
ns1 192.168.5.21 ns1.corpzone.lan BIND Master
ns2 192.168.5.22 ns2.corpzone.lan BIND Slave
Логика проста. Имя ns1 закрепляется за мастером, ns2 за подчинённым. Оба входят во внутренний домен corpzone.lan, который выполняет роль примера и легко заменяется на свой собственный. Зона .lan традиционно используется для локальных корпоративных сетей и не пересекается с публичным DNS, что и нужно для частной инфраструктуры.
Подключаемся к первому серверу и задаём ему имя:
sudo hostnamectl set-hostname ns1.corpzone.lan
Команда hostnamectl - это утилита из systemd, которая корректно записывает имя хоста сразу в несколько мест. Она обновляет файл /etc/hostname, текущее имя в ядре и информацию для D-Bus. Раньше для этого требовалось править несколько файлов вручную, но времена изменились к лучшему.
Те же манипуляции нужно повторить на втором сервере:
sudo hostnamectl set-hostname ns2.corpzone.lan
Дальше открываем файл сопоставления имён и адресов:
sudo nano /etc/hosts
Добавляем туда записи для обоих узлов:
192.168.5.21 ns1.corpzone.lan ns1
192.168.5.22 ns2.corpzone.lan ns2
Сохраняем и выходим. Зачем это нужно, если мы только что собираемся поднять полноценный DNS? Парадокс лишь кажущийся. До того момента, пока BIND не запущен и не настроен, серверы должны как-то находить друг друга. Файл /etc/hosts - старая надёжная карта, которая работает всегда, независимо от состояния служб разрешения имён. После запуска BIND содержимое hosts будет обрабатываться раньше DNS, что в нашем случае только на руку.
Проверяем результат на каждом сервере:
sudo hostname -f
На первом узле вывод покажет ns1.corpzone.lan, на втором - ns2.corpzone.lan. Если что-то пошло не так, проверяй последовательность - сначала hostnamectl, потом /etc/hosts, потом проверка через hostname -f.
Установка пакетов BIND9 и сопутствующих утилит из стандартного репозитория Ubuntu
Хорошая новость - BIND присутствует в стандартных репозиториях Ubuntu, никаких сторонних PPA подключать не нужно. Эта установка стабильно работает у всех, кто хоть раз поднимал DNS на Debian-подобных системах.
Обновляем индекс пакетов на обоих серверах:
sudo apt update
Команда обращается к серверам репозитория и подтягивает свежий список доступных пакетов и их версий. Без этого шага apt может попытаться установить устаревшую версию или вообще не найти нужный пакет, если индекс давно не обновлялся.
Теперь ставим всё необходимое:
sudo apt install bind9 bind9utils bind9-doc dnsutils
При запросе подтверждения нажимаем Y и Enter. Разберём, что именно ставится. Пакет bind9 - это сам сервер, основной демон named и его конфигурация. bind9utils содержит набор инструментов администратора, среди которых утилиты проверки конфигов и зон вроде named-checkconf и named-checkzone. Пакет bind9-doc приносит документацию, которая может пригодиться при сложной отладке. Наконец, dnsutils даёт классический набор клиентских команд - dig, nslookup, host. Без них тестировать DNS-сервер было бы крайне неудобно.
После завершения установки правим файл с параметрами запуска службы:
sudo nano /etc/default/named
В этом файле есть строка OPTIONS, через которую передаются аргументы при старте демона. Поскольку IPv6 в нашем сценарии не используется, имеет смысл явно указать запуск только по IPv4:
OPTIONS="-u bind -4"
Флаг -u bind означает, что демон будет работать от непривилегированного пользователя bind, а -4 ограничивает прослушивание четвёртой версией протокола. Сохраняем файл и закрываем редактор.
Перезапускаем службу и проверяем её состояние:
sudo systemctl restart named
sudo systemctl status named
Вывод должен показать active (running) зелёным. Если статус failed или служба не стартует, первым делом смотри журнал через journalctl -u named -n 50, там обычно лежит подсказка о причине. Чаще всего проблемы связаны с правами на каталоги или синтаксической ошибкой в файлах конфигурации.
Настройка первого сервера в роли мастера и описание списков контроля доступа
Когда пакеты установлены и служба бодро отвечает, наступает время превратить ns1 в полноценный мастер-сервер. Можно было бы ограничиться одним узлом, но единая точка отказа в инфраструктуре - источник вечной головной боли. Связка мастер-подчинённый как раз решает проблему отказоустойчивости и попутно распределяет нагрузку при больших объёмах запросов.
Возвращаемся в терминал ns1 и открываем главный конфигурационный файл с опциями:
sudo nano /etc/bind/named.conf.options
В самое начало файла, до блока options { ... };, добавляем определение списка контроля доступа:
acl "trusted" {
192.168.5.21; # ns1 - or you can use localhost for ns1
192.168.5.22; # ns2
192.168.5.0/24; # trusted networks
};
ACL под названием trusted объединяет все доверенные адреса и подсети. Сюда входит сам мастер-сервер ns1, подчинённый ns2 и вся локальная сеть 192.168.5.0/24. Дальше этот список будет использоваться для ограничения рекурсивных запросов - чужакам разрешать рекурсию категорически нельзя, иначе сервер превратится в инструмент для атак с усилением трафика.
Теперь правим сам блок options следующим образом:
options {
directory "/var/cache/bind";
//listen-on-v6 { any; }; # disable bind on IPv6
recursion yes; # enables resursive queries
allow-recursion { trusted; }; # allows recursive queries from "trusted" - referred to ACL
listen-on { 192.168.5.21; }; # ns1 IP address
allow-transfer { none; }; # disable zone transfers by default
forwarders {
8.8.8.8;
1.1.1.1;
};
};
Разбор по строкам стоит того, чтобы задержаться на каждой. Параметр directory указывает рабочий каталог демона, куда он будет складывать временные файлы и кеш. Закомментированная строка listen-on-v6 отключает IPv6, поскольку мы условились работать только с четвёртой версией. Включение recursion позволяет серверу обрабатывать рекурсивные запросы, то есть искать ответы у других серверов, если своих данных недостаточно.
Параметр allow-recursion ограничивает рекурсию только списком trusted - именно поэтому ACL и определяется первым. Опция listen-on привязывает службу к конкретному IP-адресу мастера, что даёт чёткое управление сетевыми интерфейсами. Параметр allow-transfer со значением none отключает передачу зон по умолчанию для всех; разрешения будут прописаны явно для конкретных зон чуть позже. Это правило золотое - открывать передачу зон нараспашку нельзя ни при каких обстоятельствах.
Блок forwarders определяет внешние DNS-серверы, к которым BIND будет обращаться при запросах вне своих зон. Здесь указаны Google Public DNS (8.8.8.8) и Cloudflare (1.1.1.1). Можно использовать и другие резолверы - выбор зависит от политик компании и требований к скорости отклика.
Сохраняем файл, после чего проверяем синтаксис:
sudo named-checkconf /etc/bind/named.conf.options
Утилита named-checkconf отрабатывает молча, если всё в порядке. Любой вывод обычно означает проблему - и обычно с указанием строки, где она затаилась.
Создание прямой и обратной зон для собственного домена с описанием SOA, NS, A и MX записей
Теперь самое интересное - описание зон. Зона в DNS это что-то вроде паспортного стола, где хранятся все записи об именах и адресах конкретного домена. Различают две разновидности - прямые и обратные. Прямая зона связывает имя с IP, обратная решает противоположную задачу: по адресу выдаёт имя.
Открываем файл локальных зон:
sudo nano /etc/bind/named.conf.local
Прописываем в нём оба типа зон:
zone "corpzone.lan" {
type master;
file "/etc/bind/zones/db.corpzone.lan"; # zone file path
allow-transfer { 192.168.5.22; }; # ns2 IP address - secondary DNS
};
zone "5.168.192.in-addr.arpa" {
type master;
file "/etc/bind/zones/db.192.168.5"; # subnet 192.168.5.0/24
allow-transfer { 192.168.5.22; }; # ns2 private IP address - secondary DNS
};
Первый блок описывает прямую зону для домена corpzone.lan, второй обратную для подсети 192.168.5.0/24. Обратная зона записывается задом наперёд с добавлением суффикса .in-addr.arpa - такова традиция, идущая ещё со времён ранних RFC. Параметр allow-transfer для каждой зоны отдельно разрешает передачу только подчинённому серверу ns2 по адресу 192.168.5.22.
Создаём каталог для файлов зон:
sudo mkdir -p /etc/bind/zones/
Копируем шаблон прямой зоны и открываем для правки:
sudo cp /etc/bind/db.local /etc/bind/zones/db.corpzone.lan
sudo nano /etc/bind/zones/db.corpzone.lan
Содержимое файла приводим к такому виду:
;
; BIND data file for the local loopback interface
;
$TTL 604800
@ IN SOA ns1.corpzone.lan. admin.corpzone.lan. (
3 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
; NS records for name servers
IN NS ns1.corpzone.lan.
IN NS ns2.corpzone.lan.
; A records for name servers
ns1.corpzone.lan. IN A 192.168.5.21
ns2.corpzone.lan. IN A 192.168.5.22
; Mail handler or MX record for the domain corpzone.lan
corpzone.lan. IN MX 10 mail.corpzone.lan.
; A records for domain names
corpzone.lan. IN A 192.168.5.100
mail.corpzone.lan. IN A 192.168.5.120
Здесь каждая запись отвечает за свою задачу. Параметр $TTL задаёт время жизни записей по умолчанию - 604800 секунд это ровно неделя. SOA (Start of Authority) - визитная карточка зоны, в ней указан главный сервер, контактный почтовый адрес администратора (записанный с точкой вместо @ - чисто историческая особенность синтаксиса) и набор таймеров.
Поле Serial - это серийный номер версии зоны. Любое изменение в файле требует увеличения этого числа, иначе подчинённые серверы не поймут, что данные обновились. Многие администраторы используют формат YYYYMMDDNN, где последние две цифры - порядковый номер изменения за день. Удобно при отладке и для аудита.
Refresh определяет, как часто подчинённые серверы будут проверять актуальность данных у мастера. Retry задаёт паузу между повторами, если связь с мастером оборвалась. Expire говорит, сколько времени подчинённый продолжит обслуживать зону, если мастер вообще исчезнет. Negative Cache TTL отвечает за кеширование отрицательных ответов - например, когда запрашивается несуществующее имя.
Записи NS перечисляют авторитативные серверы для зоны. Записи A связывают имя с IPv4-адресом. Запись MX указывает почтовый обработчик для домена с приоритетом 10 - чем меньше число, тем выше приоритет. Если почтовых серверов несколько, разные приоритеты позволяют распределять нагрузку или строить резервные маршруты доставки.
Теперь делаем то же самое для обратной зоны:
sudo cp /etc/bind/db.127 /etc/bind/zones/db.192.168.5
sudo nano /etc/bind/zones/db.192.168.5
Содержимое:
;
; BIND reverse data file for the local loopback interface
;
$TTL 604800
@ IN SOA ns1.corpzone.lan. admin.corpzone.lan. (
3 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
; name servers - NS records
IN NS ns1.corpzone.lan.
IN NS ns2.corpzone.lan.
; PTR Records
21 IN PTR ns1.corpzone.lan. ; 192.168.5.21
22 IN PTR ns2.corpzone.lan. ; 192.168.5.22
100 IN PTR corpzone.lan. ; 192.168.5.100
120 IN PTR mail.corpzone.lan. ; 192.168.5.120
Запись PTR работает в обратном направлении по сравнению с A - принимает на вход последний октет IP-адреса (для подсети /24) и выдаёт связанное с ним имя. Многие почтовые серверы в интернете требуют наличия корректной PTR-записи для отправляющего узла, иначе письма летят прямиком в спам. В локальных сетях обратные запросы тоже бывают полезны, особенно при анализе логов и аудите подключений.
Прогоняем проверку всей конфигурации сразу:
sudo named-checkconf
Затем по очереди валидируем каждую зону:
sudo named-checkzone corpzone.lan /etc/bind/zones/db.corpzone.lan
sudo named-checkzone 5.168.192.in-addr.arpa /etc/bind/zones/db.192.168.5
Если в обоих случаях получили OK, всё в порядке. Иначе утилита покажет конкретную строку с ошибкой - чаще всего это забытая точка в конце доменного имени или описка в имени записи.
Перезапускаем службу для применения настроек мастера:
sudo systemctl restart named
Превращение второго сервера во вторичный DNS с автоматическим получением зон от мастера
С мастером покончено, переходим к ns2. Логика подчинённого сервера принципиально иная - он не хранит постоянные файлы зон, а получает их от мастера и держит у себя временные копии. Если данные на мастере меняются, slave автоматически забирает обновление по протоколу AXFR (полная передача) или IXFR (инкрементальная). Преимущество налицо - конфигурацию правишь в одном месте, а изменения разъезжаются по всем серверам.
Подключаемся к ns2 и открываем файл опций:
sudo nano /etc/bind/named.conf.options
В верхней части файла добавляем точно такой же ACL, как на мастере:
acl "trusted" {
192.168.5.21; # ns1
192.168.5.22; # ns2 - or you can use localhost for ns2
192.168.5.0/24; # trusted networks
};
Блок options оформляем аналогично мастеру, меняя только адрес прослушивания на собственный:
options {
directory "/var/cache/bind";
//listen-on-v6 { any; }; # disable bind on IPv6
recursion yes; # enables resursive queries
allow-recursion { trusted; }; # allows recursive queries from "trusted" - referred to ACL
listen-on { 192.168.5.22; }; # ns2 IP address
allow-transfer { none; }; # disable zone transfers by default
forwarders {
8.8.8.8;
1.1.1.1;
};
};
Сохраняем и закрываем. Теперь правим описание зон:
sudo nano /etc/bind/named.conf.local
Содержимое:
zone "corpzone.lan" {
type slave;
file "/etc/bind/zones/db.corpzone.lan";
masters { 192.168.5.21; }; # ns1 IP address - master DNS
};
zone "5.168.192.in-addr.arpa" {
type slave;
file "/etc/bind/zones/db.192.168.5";
masters { 192.168.5.21; }; # ns1 IP address - master DNS
};
Ключевые отличия от мастер-конфигурации - тип zone установлен в slave и появилась директива masters, указывающая, откуда забирать данные. Создавать сами файлы зон вручную не нужно: они появятся в каталоге автоматически после первой удачной передачи зоны от мастера.
Проверяем синтаксис и перезапускаем службу:
sudo named-checkconf
sudo systemctl restart named
Затем убеждаемся, что демон поднялся:
sudo systemctl status named
Если в логах через journalctl -u named появляются строки про zone transfer success или похожие, значит, передача зон уже состоялась. Если же видны ошибки про refused или timed out - проверь, открыт ли порт 53 на мастере, и совпадают ли IP-адреса в allow-transfer на стороне ns1 с реальным адресом ns2.
Проверка работы DNS-сервера со стороны клиентской машины через dig и nslookup
Финальная стадия - убедиться, что инфраструктура отвечает на запросы извне. Для теста подойдёт любая машина в той же локальной сети, главное чтобы она могла обратиться к адресам 192.168.5.21 и 192.168.5.22.
Простейший способ настроить резолвер - перезаписать файл /etc/resolv.conf. Способ неуниверсальный (на современных Ubuntu есть systemd-resolved и NetworkManager со своими привычками), но для проверки годится отлично.
Удаляем символическую ссылку и создаём обычный файл:
sudo unlink /etc/resolv.conf
sudo nano /etc/resolv.conf
Заполняем его:
nameserver 192.168.5.21
nameserver 192.168.5.22
nameserver 8.8.8.8
search corpzone.lan
Здесь резолверы перебираются сверху вниз - сначала мастер, потом подчинённый, потом публичный Google DNS на случай полной недоступности своих серверов. Параметр search автоматически дописывает указанный домен к коротким именам, что удобно для повседневной работы.
Ставим утилиты диагностики:
sudo apt install dnsutils bind9-utils
Проверяем разрешение основного домена:
dig corpzone.lan +short
dig corpzone.lan
Флаг +short выводит только сам ответ без служебных заголовков - удобно для скриптов и быстрых проверок. Полный вывод dig содержит много полезной информации: время ответа, использованный сервер, флаги ответа, секции вопросов и ответов. Если в выводе видно ANSWER: 192.168.5.100 - всё работает как задумано.
Проверяем поддомен:
dig mail.corpzone.lan +short
dig mail.corpzone.lan
Должен вернуться адрес 192.168.5.120. Дальше переходим к MX-записи:
dig corpzone.lan MX +short
dig corpzone.lan MX
В ответе должна появиться строка с приоритетом 10 и именем mail.corpzone.lan. Это означает, что почтовые системы, обращающиеся к нашему домену, будут знать, куда стучаться.
Проверяем работу обратной зоны через nslookup:
nslookup 192.168.5.21
nslookup 192.168.5.22
nslookup 192.168.5.100
nslookup 192.168.5.120
Каждый запрос должен возвращать соответствующее имя - ns1.corpzone.lan, ns2.corpzone.lan, corpzone.lan и mail.corpzone.lan. Если что-то не сходится, чаще всего виновата невнимательность в файле обратной зоны: либо забыта точка в конце имени, либо неверно указан последний октет.
Распространённые ошибки настройки и практические сценарии применения BIND в реальной инфраструктуре
В копилку наблюдений из практики стоит добавить несколько моментов, на которых спотыкаются почти все, кто впервые поднимает BIND. Самая популярная грабля - забытая точка в конце полного доменного имени внутри файлов зон. Без точки BIND считает имя относительным и автоматически дописывает к нему имя зоны, превращая ns1.corpzone.lan в ns1.corpzone.lan.corpzone.lan. Поначалу это сбивает с толку, но привычка ставить точку формируется быстро.
Вторая по популярности проблема - забытое увеличение Serial при правке зоны. Вроде бы изменил A-запись на мастере, перезапустил службу, а на подчинённом всё по-старому. Причина в том, что slave сравнивает серийные номера и не видит причин обновляться. Лечится педантичным инкрементом Serial при каждом изменении.
Третья типичная история связана с настройками файрвола. Если на мастере включен ufw или iptables и порт 53 закрыт для подчинённого, передача зон не пройдёт. Причём dig с самого мастера будет работать прекрасно, и это создаёт ложное ощущение, что всё в порядке. При диагностике проблем с репликацией всегда нужно проверять не только конфиги BIND, но и сетевые правила.
Где такая связка пригодится в реальной жизни? Случаев масса. Внутренние корпоративные ресурсы, до которых нельзя долетать через публичный DNS - проектная документация, системы автоматизации сборок, мониторинг, инвентаризация. Лабораторные стенды для разработчиков, где нужно быстро поднимать и сносить домены без обращения к регистратору. Распределённые офисы, где локальный DNS снижает задержки и трафик к публичным резолверам. Среды Kubernetes и Docker, где сервисное имя должно резолвиться в адрес балансировщика без лишних прослоек.
Освоение BIND даёт инженеру не просто навык настройки одной программы, а понимание того, как работает разрешение имён в принципе. Это знание переносимо - такие концепции, как авторитативные ответы, рекурсия, передача зон и кеширование, лежат в основе любого DNS-сервера, будь то PowerDNS, Knot, Unbound или коммерческие решения вроде Infoblox. Тот, кто разобрался с BIND9, без труда освоит любой из конкурентов, поскольку отличия будут только в синтаксисе конфигов, а не в идеологии. И именно поэтому BIND продолжает оставаться неофициальным стандартом, который изучают первым - он показывает DNS таким, какой он есть, без излишних абстракций и упрощений.