Когда в инфраструктуре появляется два-три сервера, можно ещё обходиться файлом /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 таким, какой он есть, без излишних абстракций и упрощений.