Классическая задача для админа: одинаковые имена, разные адреса для разных сред. Командам DEV нужны тестовые IP, STAGE — предбоевые, PROD — только боевые. Плюс приходится прятать внутренние сервисы от внешнего мира. Решение — split‑horizon DNS в BIND через механизм views, когда сервер выбирает зону и ответы в зависимости от того, кто спрашивает.
Зачем split‑horizon и как это работает в BIND
Split‑horizon DNS — это подход, при котором один и тот же домен (или имя) разрешается в разные IP в зависимости от клиента. В BIND это реализуется с помощью view: каждая view имеет свои ACL (match-clients), настройки рекурсии, свой кэш и собственные описания зон. По сути, вы поднимаете несколько «логических» DNS‑серверов внутри одного процесса.
Важно понимать, что порядок view в конфигурации имеет значение: BIND выбирает первую подходящую по match-clients. Ещё момент: у каждой view независимый кэш, что помогает избежать «протечек» записей между средами, но накладывает ответственность за отдельную диагностику и очистку кэша.
Если вы выбираете стек, посмотрите сравнение PowerDNS и BIND — это поможет принять решение на старте проекта.
Архитектурные варианты для DEV/STAGE/PROD
1) Один FQDN с разными ответами
Наиболее «чистый» split‑horizon: имя api.example.com в view DEV указывает на IP DEV, в STAGE — на STAGE, в PROD — на боевой. Плюсы: одинаковые конфиги приложений (имя не меняется). Минусы: выше риск человеческой ошибки и «прострела» — если перепутать файлы зон или ACL, можно отдать тестовый адрес в прод или наоборот.
2) Раздельные подзоны dev.example.com, stage.example.com
Консервативный подход: разные имена для разных сред. Он проще в обслуживании и понятнее новичкам, но требует дисциплины в приложениях (URL/конфиги отличаются между средами). Внутри views можно дополнительно скрывать внутренние подзоны от нецелевых сетей.
На практике часто комбинируют: единый FQDN с разными ответами для внутренних сетей и отдельные подзоны для внешних партнёров/аутсорсеров.
Поднимать авторитативный DNS удобнее на изолированном узле, например на VDS, где проще контролировать сеть, фаервол и обновления.
Проектирование ACL и критериев маршрутизации
Ключевой слой — ACL, по которым BIND определяет, в какую view отправить запрос. Обычно это:
- Подсети разработчиков и CI (DEV).
- STAGE‑сегменты, предбоевые кластеры, UAT‑VPN.
- PROD‑сети (офис, дата‑центры, DMZ) и «все прочие».
Рекомендации:
- Чётко документируйте диапазоны IP и держите один источник истины (например, отдельный include-файл
acls.conf). - Ставьте наиболее «специфичные» ACL выше в списке views.
- Не полагайтесь на
match-destinationsбез необходимости — обычно достаточноmatch-clients. - Не используйте
.localкак TLD для внутренних зон (резерв mDNS). Лучшеcorp.example.comлибо.internalбез делегирования наружу.

Базовая конфигурация BIND с views
Ниже — опорный пример. Адаптируйте имена зон, пути и сети под себя. Показан вариант, где один и тот же домен example.com имеет разные файлы зоны в DEV/STAGE/PROD. Добавлен «default» для всех прочих клиентов, чтобы отдавать только публично безопасный ответ.
# /etc/named.conf (или /etc/bind/named.conf)
acl devnets { 10.10.0.0/16; 172.16.10.0/24; };
acl stagenets { 10.20.0.0/16; 172.16.20.0/24; };
acl prodnets { 10.30.0.0/16; 192.168.100.0/24; };
options {
directory "/var/named";
listen-on { 0.0.0.0; };
listen-on-v6 { any; };
allow-query { any; };
allow-recursion { none; };
dnssec-enable yes;
dnssec-validation auto;
};
logging {
channel default_syslog { syslog daemon; severity info; };
category default { default_syslog; };
category queries { default_syslog; };
};
key "xfr-key" {
algorithm hmac-sha256;
secret "BASE64==";
};
server 192.0.2.2 { keys { xfr-key; }; };
view "dev" {
match-clients { devnets; 127.0.0.1; ::1; };
recursion yes;
allow-recursion { devnets; localhost; };
zone "example.com" IN {
type master;
file "zones/dev.example.com.zone";
allow-transfer { key xfr-key; 192.0.2.2; };
notify yes;
also-notify { 192.0.2.2; };
};
};
view "stage" {
match-clients { stagenets; };
recursion yes;
allow-recursion { stagenets; };
zone "example.com" IN {
type master;
file "zones/stage.example.com.zone";
allow-transfer { key xfr-key; 192.0.2.2; };
notify yes;
also-notify { 192.0.2.2; };
};
};
view "prod" {
match-clients { prodnets; };
recursion no;
zone "example.com" IN {
type master;
file "zones/prod.example.com.zone";
allow-transfer { key xfr-key; 192.0.2.2; };
notify yes;
also-notify { 192.0.2.2; };
};
};
view "default" {
match-clients { any; };
recursion no;
zone "example.com" IN {
type master;
file "zones/public.example.com.zone";
};
};
Комментарий к важным опциям:
allow-recursionвключаем только там, где реально нужно резолвить внешние записи (обычно для DEV/STAGE). В PROD для авторитативного ответчика —no.allow-transferиalso-notifyограничиваем и защищаем TSIG‑ключом. Не отдавайте трансферы без аутентификации.view "default"— страховка, чтобы «все остальные» не увидели внутренние адреса.
Шаблоны зон, TTL и различия между средами
Для DEV логично делать маленькие TTL (30–300 секунд) — удобно тестировать. Для PROD TTL выше (5–30 минут, иногда больше) — меньше нагрузка и колебания. Следите за SOA: увеличивайте serial при каждом изменении, выставляйте разумный negative TTL (поле SOA, второе справа) — например 60–300 секунд в DEV/STAGE и 300–900 в PROD.
;; zones/dev.example.com.zone
$TTL 60
@ IN SOA ns1.example.com. dns.example.com. (
2025102301 ; serial
1h ; refresh
10m ; retry
7d ; expire
60 ; negative TTL
)
IN NS ns1.example.com.
IN A 10.10.10.10
www IN A 10.10.10.20
api IN A 10.10.10.30
;; zones/stage.example.com.zone
$TTL 120
@ IN SOA ns1.example.com. dns.example.com. (
2025102301 1h 10m 7d 120
)
IN NS ns1.example.com.
IN A 10.20.20.10
www IN A 10.20.20.20
api IN A 10.20.20.30
;; zones/prod.example.com.zone
$TTL 900
@ IN SOA ns1.example.com. dns.example.com. (
2025102301 1h 10m 7d 300
)
IN NS ns1.example.com.
IN A 203.0.113.10
www IN A 203.0.113.20
api IN A 203.0.113.30
;; zones/public.example.com.zone (минимум, что безопасно отдать всем)
$TTL 900
@ IN SOA ns1.example.com. dns.example.com. (
2025102301 1h 10m 7d 300
)
IN NS ns1.example.com.
www IN A 203.0.113.20
Обратите внимание: если публичная зона делегирована у регистратора и подписана DNSSEC, то подход «одна и та же зона, разные ответы» требует особой аккуратности. Валидация может ломаться, если версии зоны внутри и снаружи подписаны по‑разному. Безопасная стратегия — держать публичную делегируемую зону с консистентной подписью, а внутренние ответы отдавать только внутренним сетям либо использовать отдельные подзоны. Если домен ещё не оформлен, начните с регистрации доменов, продумав делегирование и NS заранее.
Проверка конфигурации и публикация
Перед перезапуском прогоним валидацию:
named-checkconf -z
named-checkzone example.com /var/named/zones/dev.example.com.zone
named-checkzone example.com /var/named/zones/stage.example.com.zone
named-checkzone example.com /var/named/zones/prod.example.com.zone
named-checkzone example.com /var/named/zones/public.example.com.zone
Загружаем/перечитываем:
rndc reconfig
rndc reload
Тестируем из каждой подсети. Удобно использовать dig с привязкой исходного адреса (на хосте, где есть такие IP), либо запускать команды непосредственно из соответствующих сетевых зон.
dig @127.0.0.1 api.example.com +short
# С указанным исходным адресом (если интерфейс есть на сервере)
dig -b 10.10.0.10 @127.0.0.1 api.example.com +short # ожидаем DEV IP
dig -b 10.20.0.10 @127.0.0.1 api.example.com +short # ожидаем STAGE IP
dig -b 10.30.0.10 @127.0.0.1 api.example.com +short # ожидаем PROD IP
Если видите неожиданные ответы, проверьте порядок view, ACL и наличие продублированных записей. Для очистки кэша по имени в конкретной view:
rndc flushname -view dev api.example.com
rndc flushname -view stage api.example.com
rndc flushname -view prod api.example.com

AXFR/IXFR и резервные NS при views
Если у вас вторичные DNS, они тоже должны «понимать» нужные варианты зон. Есть два пути:
- Поднять аналогичную конфигурацию
viewsна вторичном, чтобы принимать соответствующие трансферы из каждойview. - Поддерживать разные имена зон/файлы и изолировать потоки трансферов по IP и TSIG‑ключам. Следите, чтобы вторичный отдавал клиентам те же ответы согласно своим
views.
И не забывайте, что notify и allow-transfer настраиваются внутри каждой view, иначе второй сервер может получить не ту версию зоны.
Рекурсия, фильтры и внутренние зоны
Для внутренних клиентов обычно нужен рекурсивный резолв внешних доменов. Включайте recursion только там, где это действительно требуется, и ограничивайте allow-recursion. Внутренние зоны сервисов (например, internal.corp.example.com) добавляются как обычные zone внутри нужных views. Полезны «пустые зоны» RFC 1918/6303 для блокировки утечек PTR‑запросов наружу.
DNSSEC и split‑horizon
DNSSEC с views — тонкая тема. Отдавать разные данные под одной делегированной и подписанной зоной разным клиентам рискованно: валидаторы вне вашей сети могут получать RRSIG, не соответствующие данным. Безопасные стратегии:
- Публичную зону держать консистентной и подписанной, а внутренние ответы — в непубличных подзонах без делегирования наружу.
- Либо поддерживать отдельные делегирования и ключи для внутренних версий зон, изолированные от публичной цепочки доверия.
Если всё же требуется inline‑signing по views, тщательно протестируйте валидацию и кэширование со стороны внешних и внутренних резолверов. Для автоматизации DNS‑01 и wildcard‑сертификатов пригодится материал «Wildcard и DNS‑01: автоматизация».
Типичные ошибки и как их избежать
- Неверный порядок
view: «широкая»anyраньше «узкой» — все попадают не туда. - Забытый
allow-queryилиallow-transferна уровне зоны внутри нужнойview. - Необновлённый
SOA serial— вторички не получают изменения. - Слишком большие TTL в DEV/STAGE — медленная обратная связь при тестах.
- Клиенты используют сторонние публичные резолверы, минуя ваш split‑horizon. Решение — политика на уровне DHCP/резолверов/файрвола.
- NAT hairpin/loopback и асимметричная маршрутизация ломают
match-clients. Тестируйте из реальных подсетей. - Смешение рекурсивного и авторитативного режимов без чётких границ
allow-recursion.
Миграция с «одной зоны» на views без простоя
- Соберите список клиентов и сетей, которые должны видеть DEV/STAGE/PROD.
- Создайте ACL и черновики файлов зон для каждой среды.
- Добавьте
view "default"с безопасной публичной зоной, но пока не переключайте клиентов. - Включите
viewsна одном из вторичных серверов и проверьте консистентность трансферов. - Разверните
viewsна основном, но временно включите повышенный лог запросов (category queries), проверьте тестами. - Переключите клиентов по сегментам, проверяя
dig/rndcи метрики. - Зафиксируйте итоговую схему, отключите лишнюю детализацию логов.
Эксплуатационные советы
- Автоматизируйте проверку:
named-checkconf -zиnamed-checkzoneв CI перед выкладкой зон в репозиторий. - Шаблонизируйте SOA и TTL. Единый стиль ускоряет ревью.
- Используйте
rndc reconfigдля подхвата новых зон без полной перезагрузки, аrndc reload— для пересборки конкретной зоны. - Для ускорения массовых правок в DEV/STAGE держите TTL низкими и повышайте только перед релизом.
- Помните про независимые кэши per‑view: чистка точечная через
rndc flushname -view.
Итоги
Split‑horizon DNS на BIND через views — надёжная стратегия для разделения DEV/STAGE/PROD и внутренних зон. Ключ к успеху — корректные ACL, грамотный порядок view, дисциплина с TTL и SOA, защищённые трансферы и аккуратность с DNSSEC. Потратьте время на проектирование, автоматизируйте проверку и выкладку зон — и получите предсказуемые резолвы для всех сред без сюрпризов в продакшене.


