Debian Jessie: DNS Server — установка и настройка Bind9

Это заметка из цикла стетей моего небольшого HowTo по Debian Jessie.

Для начала установим необходимые пакеты:

gw~$ sudo apt-get install bind9 bind9-host bind9utils

А также добавим bind9 в автозагрузку:

gw~$ sudo systemctl enable bind9

Дальше настройка.
Опишу несколько вариантов, чтоб дать возможность каждому понять что и как настраивать, а вы уже сами выбирайте что вам больше подходит:
1. Кэширующий DNS сервер
2. Внутренние зоны
3. Внешние зоны
4. Передача/прием зон (настройка режима master/slave)

Поехали …

1. Кэширующий DNS сервер
Просто поставить Bind9 и настроить его в режиме кэширующего резолвера — уже огромный плюс! Это ускорит резолв, а следовательно и браузинг … да и всё что касается работы с Интернетом. Также это экономит траффик и ресурсы DNS серверов, так как количество обращений к ним падает в разы.
Настроить такой режим очень просто. Открываем конфиг /etc/bind/named.conf.options

gw~$ sudo vim /etc/bind/named.conf.options

и добавляем туда DNS сервера нашего провайдера. Помните провайдер выдает вам IP адрес, маску подсети, шлюз и DNS сервера? Именно эти DNS сервера нам сейчас и нужны, также для подстраховки можно добавить после DNS-ов провайдера еще и публичные DNS-ы google. Всё это вписывается в параметр forwarders Также обратите внимание на параметр listen-on — он определяет на каких интерфейсам будет запущен bind. Для кэширующего DNS тут нужно перечислить локальный и все внутренние интерфейсы. Внешние интерфейсы сюда вписывать не стоит, мы же не хотим чтобы весь Интернет имел возможность через наш DNS резолвить адреса 🙂
Итак, конфиг у меня получится вот такой:

options {
    directory "/var/cache/bind";

    // If there is a firewall between you and nameservers you want
    // to talk to, you may need to fix the firewall to allow multiple
    // ports to talk.  See http://www.kb.cert.org/vuls/id/800113

    // If your ISP provided one or more IP addresses for stable
    // nameservers, you probably want to use them as forwarders.
    // Uncomment the following block, and insert the addresses replacing
    // the all-0's placeholder.

    forwarders {
       195.20.20.20; 195.20.20.250; 8.8.4.4; 8.8.8.8;
    };

    //===================================================================
    // If BIND logs error messages about the root key being expired,
    // you will need update your keys. See https://www.isc.org/bind-keys
    //===================================================================
    dnssec-validation auto;

    auth-nxdomain no;    # conform to RFC1035
    listen-on-v6 { no; };
    listen-on { 127.0.0.1; 192.168.1.1; };
    version "7";
};

Сохраняем конфиг, перезапускаем сервис:

gw~$ sudo systemctl restart bind9

В итоге мы получаем кэширующий DNS сервер. Убедимся в этом с помощью утилиты dig:

gw~$ dig @127.0.0.1 bbc.com
; <<>> DiG 9.9.3-2+deb8u3-Debian <<>> @127.0.0.1 bbc.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43628
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 13, ADDITIONAL: 16

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;bbc.com.           IN  A

;; ANSWER SECTION:
bbc.com.        9   IN  A   212.58.246.104
bbc.com.        9   IN  A   212.58.244.18
bbc.com.        9   IN  A   212.58.244.20
bbc.com.        9   IN  A   212.58.246.103

;; AUTHORITY SECTION:
com.            10178   IN  NS  i.gtld-servers.net.
............

ответ мы получили, значит все работает как надо. Напомню, что пример настройки DHCP-сервера уже содержит данный DNS сервер как основной и единственный для клиентов локальной сети. Если же вы по какимто причинам не хотите настраивать себе DHCP сервер, не забудьте вручную на данном сервере и на компах локальной сети сменить DNS сервера в конфиге /etc/resolv.conf. Теперь он может выглядеть следующим образом:

gw~$ cat /etc/resolv.conf
domain my.local
search my.local
nameserver 127.0.0.1
gw~$

2. Внутренние зоны
Кроме того что мы настроили в первом варианте нам еще нужно подправить пару конфигов.
Если вы совсем незнакомы с настройкой DNS, без понятия что такое зона DNS и как она описывается — прочтите тут пункт «25.6.6.2. Файлы зон»
Для начала создадим файл в котором опишем нашу внутреннюю зону:

gw~$ sudo vim /etc/bind/my_local.db

и пишем туда вот что:

$TTL 3600 ; 1 hour default TTL
my.local.    IN    SOA    ns1.my.local. admin.my.local. (
                              2015042009 ; Serial
                              8H ; Refresh
                              1H ; Retry
                              1W ; Expire
                              1D ) ; minimum, seconds

; DNS Servers
          IN    NS    ns1.my.local.
; MX Records
;;        IN    MX 10 mail.my.local.
; HOST A
ns1       IN    A     192.168.1.1
gw        IN    A     192.168.1.1
ntp       IN    A     192.168.1.1
popcorn   IN    A     192.168.1.14
nb        IN    A     192.168.1.17
ws1       IN    A     192.168.1.21
torrent   IN    A     192.168.1.100
nas       IN    A     192.168.1.100
ap        IN    A     192.168.1.111
sw        IN    A     192.168.1.254
; CNAME
www       IN   CNAME  gw.my.local.

Но на данный момент это просто файлик, нужно его еще включить в конфиг bind. Для этого открываем конфиг /etc/bind/named.conf.local

gw~$ sudo vim /etc/bind/named.conf.local

и в конец добавляем вот что:

//
// My Internal Domains
//
zone "my.local" {
   type master;
   file "/etc/bind/my_local.db";
   notify no;
   allow-transfer { none; };
   allow-update { none; };
   allow-query { 127.0.0.1; 192.168.1.0/24; };
};

Сохраняем конфиг и перезапускаем сервис:

gw~$ sudo systemctl restart bind9

Пробуем отрезолвить какойто host из локалки:

gw~$ dig @127.0.0.1 nas.124.local |sed 's/124.local/my.local/g'

; <<>> DiG 9.9.5-9+deb8u3-Debian <<>> @127.0.0.1 nas.my.local
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16697
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;nas.my.local.          IN  A

;; ANSWER SECTION:
nas.my.local.       3600    IN  A   192.168.1.5

;; AUTHORITY SECTION:
my.local.       3600    IN  NS  ns1.my.local.

;; ADDITIONAL SECTION:
ns1.my.local.       3600    IN  A   192.168.1.1

;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Tue Oct 06 07:59:32 EEST 2015
;; MSG SIZE  rcvd: 92

gw~$

Как видите, резолвится отлично!

Теперь можно приступать к внешним зонам, если они у вас есть конечно 🙂

3. Внешние зоны
В первом пункте, когда мы настраивали кэширующий DNS сервер, мы не прописывали в listen-on внешний адрес, а теперь нужно прописать, поскольку внешние зоны должны отдаваться сервером в мир.
Открываем конфиг /etc/bind/named.conf.options

gw~$ sudo vim /etc/bind/named.conf.options

и параметр listen-on приводим к виду (добавляем внешний адрес в список):

listen-on { 127.0.0.1; 192.168.1.1; 91.100.100.91; };

тут следует вспомнить о том что мы не настраивали правила доступа к нашему серверу, а по умолчанию всем можно всё. Значит что любой пользователь Интернета может резолвить через наш сервер любые домены (рекурсивные запросы). Это ни к чему хорошему не приведет, кроме увеличения трафика и нагрузки. Поэтому разработаем правила доступа и настроим соответсвенно этим правилам bind.
Внутренние зоны и рекурсивные запросы нужно розрешить только непосредственно серверу (127.0.0.1) и внутренней сети (192.168.1.0/24). Остальным останется только запросы к собственным зонам bind (наши внешние зоны)
В bind есть возможность прописать так званые ACL чтобы потом их использовать. Это удобно когда зон много, сетей много и неохота загромождать конфиг каждый раз перечисляя их. Но у нас всего пара зон и одна локальная сеть, поэтому мы можем сделать без ACL. Простейшим решением в нашем случае является глобально в опциях bind прописать кому розрешены рекурсивные запросы, для этого в конфиг /etc/bind/named.conf.options добавляем в конец опцию allow-recursion. В конечном итоге данный конфиг должен выглядеть вот так:

options {
    directory "/var/cache/bind";

    // If there is a firewall between you and nameservers you want
    // to talk to, you may need to fix the firewall to allow multiple
    // ports to talk.  See http://www.kb.cert.org/vuls/id/800113

    // If your ISP provided one or more IP addresses for stable
    // nameservers, you probably want to use them as forwarders.
    // Uncomment the following block, and insert the addresses replacing
    // the all-0's placeholder.

    forwarders {
       195.20.20.20; 195.20.20.250; 8.8.4.4; 8.8.8.8;
    };

    //===================================================================
    // If BIND logs error messages about the root key being expired,
    // you will need update your keys. See https://www.isc.org/bind-keys
    //===================================================================
    dnssec-validation auto;

    auth-nxdomain no;    # conform to RFC1035
    listen-on-v6 { no; };
    listen-on { 127.0.0.1; 192.168.1.1; 91.100.100.91; };
    version "7";

    // Recursion Query
    allow-recursion {
       192.168.1.0/24; 127.0.0.1;
    };
};

Сохраняем, выходим …

Теперь можно приступать к сооружению файлика зоны. В предыдущем варианте мы настроили внутреннюю зону, тут все тоже самое, просто зона другая.
Для примера я покажу как настроена зона данного блога — diff.org.ua
Открываем файлик /etc/bind/diff_org_ua.db:

gw:~$ sudo vim /etc/bind/diff_org_ua.db

И помещаем туда вот что:

$TTL 3600 ; 1 hour default TTL
diff.org.ua.    IN      SOA     ns1.diff.org.ua.  admin.diff.org.ua. (
                                2015060201 ; Serial
                                8H ; Refresh
                                1H ; Retry
                                1W ; Expire
                                1D ) ; minimum, seconds
;
; DNS Servers
                IN      NS      ns1.diff.org.ua.
                IN      NS      ns2.diff.org.ua.
; MX Records
;;              IN      MX  10  mail.diff.org.ua.
                IN      A       91.100.100.91
; SPF
;               IN      TXT     "v=spf1 +a +mx -all"
;;              IN      TXT     "v=spf1 ip4:91.100.100.91 +mx -all"
; HOST A
ns1             IN      A       91.100.100.91
ns2             IN      A       91.100.100.91
deb             IN      A       91.100.100.91
;;mail          IN      A       91.100.100.91
; CNAME Aliases
www             IN      CNAME   diff.org.ua.

Сохраняем, выходим. Итак, файл зоны мы создали, нужно его включить в конфиг bind. Для этого открываем конфиг /etc/bind/named.conf.local

gw~$ sudo vim /etc/bind/named.conf.local

и в конец добавляем вот что:

//
// My External Domains
//
zone "diff.org.ua" {
    type master;
    file "/etc/bind/diff_org_ua.db";
    notify yes;
    allow-transfer { none; };
    allow-update { none; };
};

Для того чтобы изменения вступили в силу — перезапускаем сервис bind9

gw:~$ sudo systemctl restart bind9.service

Проверочка, попробуем отрезолвить зону diff.org.ua:

gw:~$ dig @127.0.0.1 diff.org.ua

; <<>> DiG 9.9.3-8+deb8u3-Debian <<>> @127.0.0.1 diff.org.ua
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46075
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;diff.org.ua.           IN  A

;; ANSWER SECTION:
diff.org.ua.        3600    IN  A   91.100.100.91

;; AUTHORITY SECTION:
diff.org.ua.        3600    IN  NS  ns1.diff.org.ua.
diff.org.ua.        3600    IN  NS  ns2.diff.org.ua.

;; ADDITIONAL SECTION:
ns1.diff.org.ua.    3600    IN  A   91.100.100.91
ns2.diff.org.ua.    3600    IN  A   91.100.100.91

;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Oct 07 08:04:07 EEST 2015
;; MSG SIZE  rcvd: 124

gw:~$

Все отлично работает!

И последний вариант настройки …
4. Передача/прием зон
В серьезных интернет-проектах желательно иметь «запасной парашют» в виде второго DNS сервера на случай если упадет основной. Мало ли что бывает, интернет провайдер может лагонуть, сам сервис bind или сервер. Но админить одну зону на нескольких серверах неудобно, пиши изменения на первый сервер, потом на второй … Это предусмотрели разработчики bind и добавили функционал так званой передачи зон. Если у вас больше одного DNS-сервера, вам просто нужно определиться кто из них будет основным и настроить его master-ом, остальные настроить в slave-режиме и зона в случае изменения на мастере автоматически передается на все slave-сервера. Сейчас я покажу как это делается на примере своей зоны diff.org.ua.
Итак, определимся с вводными данными:
— master сервер будет 91.100.100.91 (я буду называть его просто — master)
— slave сервер будет 92.200.200.92 (я буду называть его просто — slave)
Для начала на мастере создадим директорию для ключа, ключ нужен для авторизации серверов между собой.

master:~$ sudo mkdir /etc/bind/keys

исправляем владельца этой директории:

master:~$ sudo chown bind:bind /etc/bind/keys

переходим в директорию /etc/bind:

master:~$ cd /etc/bind

генерим ключ (имя файла diff_master.key выбрано для примера, думаю в вашем случае лучше назвать этот ключ по-другому):

master:/etc/bind$ sudo dnssec-keygen -K keys -a HMAC-SHA512 -b 512 -n HOST -r /dev/urandom diff_master.key

смотрим что получилось (у вас имена файлов будут другие):

master:/etc/bind$ ls -l keys/
total 8
-rw-r--r-- 1 root root 124 Oct  9 08:12 Kdiff_master.key.+165+56734.key
-rw------- 1 root root 232 Oct  9 08:12 Kdiff_master.key.+165+56734.private
master:/etc/bind$

тут для нас важен файлик *.private, в нем содержится ключ и тип шифрования. Переименуем этот файлик:

master:/etc/bind$ sudo mv keys/Kdiff_master.key.+165+56734.private keys/diff_master.key

открываем этот файл текстовым редактором:

master:/etc/bind$ sudo vim keys/diff_master.key

и приводим его к следующему виду (на ключ не смотрите, у вас он будет другой, тут важно соблюдать формат):

key "diff_master.key" {
    algorithm HMAC-MD5;
    secret "m1h58ieF6NQtRn7Zz7wyNerrGopS9zdqqxjCkAKiSTDtf+dQOoFhQ/MoRH4NYmXc4QRMuKU1OkXbbAJb7HTH/w==";
};

server 92.200.200.92 {
    keys { diff_master.key; };
};

проверить права доступа к ключу, я сделал так:

master:/etc/bind$ sudo chown root:bind keys/diff_master.key
master:/etc/bind$ sudo chmod 440 keys/diff_master.key

ключ готов к использованию, для включения его в конфиг bind открываем файлик named.conf.local:

master:/etc/bind$ sudo vim named.conf.local

Поменять тут нужно 2 вещи, во первых включить ключ в конфигурацию, для этого добавляем вот что:

// Include Secure Key
include "/etc/bind/keys/diff_master.key";

Во-вторых нужно перенастроить зону которую мы будем передавать на slave, а точнее исправить в ней опцию allow-transfer:

zone "diff.org.ua" {
    type master;
    file "/etc/bind/diff_org_ua.db";
    notify yes;
    allow-transfer { 92.200.200.92; key "diff_master.key"; };
    allow-update { none; };
};

Сохраняем файлик, выходим. В принципе на мастере мы уже все подготовили, можно рестартонуть bind

master:~$ sudo systemctl restart bind9.service

Ну и напоследок с мастера нам нужно скопировать ключ на слейв, я сделал это командой scp, так как имел ssh доступ к серверу. Бывает так что сервер чужой и доступа нету, тут подойдет любой другой вариант: ftp, чат, почта, флешка 🙂

master:~$ sudo scp /etc/bind/keys/diff_master.key someuser@92.200.200.92:~

Теперь настройки на slave-сервере.
Итак, считаем что на slave-сервере уже настроен bind, а если не настроен — установите и настройте хотя бы так как описано в пунктах 1-3 данного howto.
Переходим в директорию /etc/bind:

slave:~$ cd /etc/bind

Тут нам нужно создать 2 директории, keys и slave:

slave:/etc/bind$ sudo mkdir keys
slave:/etc/bind$ sudo mkdir slave

Установим права на эти директории:

slave:/etc/bind$ sudo chmod 750 keys
slave:/etc/bind$ sudo chmod 755 slave

Исправляем владельца данных директорий:

slave:/etc/bind$ sudo chown root:bind keys
slave:/etc/bind$ sudo chown bind:bind slave

И небольшой финт для автороздачи прав на новые файлы в директории slave:

slave:/etc/bind$ sudo chmod g+s slave

Помещаем ключ в директорию /etc/bind/keys (тот что мы создавали на мастере):

slave:/etc/bind$ sudo mv /home/someuser/diff_master.key /etc/bind/keys

Открываем файл ключа:

slave:/etc/bind$ sudo vim keys/diff_master.key

исправляем в нем вот что:

server 92.200.200.92 {
...

на

server 91.200.200.91 {
...

Исправляем права и владельца на файл ключа:

slave:/etc/bind$ sudo chmod 440 keys/diff_master.key
slave:/etc/bind$ sudo chown root:bind keys/diff_master.key

Теперь нам нужно поправить 2 вещи в конфиге /etc/bind/named.conf.local Откроем данный конфиг:

slave:/etc/bind$ sudo vim named.conf.local

Сначала включим ключ:

// Include Secure Key
include "/etc/bind/keys/diff_master.key";

В этом же конфиге опишем зону которую мы будем принимать с master-сервера:

/// Slave Zones ///
zone "diff.org.ua" {
    type slave;
    file "/etc/bind/slave/diff_org_ua.db";
    masters { 91.100.100.91; };
    allow-notify { 91.100.100.91; };
};

Сохраняем конфиг и перезапускаем bind на slave-сервере:

master:~$ sudo systemctl restart bind9.service

Идем снова на master-сервер, открываем файл зоны diff.org.ua и добавляем к параметру «serial» +1, перезапускаем bind и смотрим что произойдет на slave сервере
В конечном итоге мы должны получить автоматически переданный файл зоны с мастера на слейв в директорию /etc/bind/slave
После этого проверьте резолвит ли слейв-сервер зону diff.org.ua и если резолвит, значит можно ключать его в данной зоне вторым NS сервером в конфиг на мастере 🙂 Для примера, окончательный вариант с двумя NS-ами на разных серверах:

$TTL 3600 ; 1 hour default TTL
diff.org.ua.    IN      SOA     ns1.diff.org.ua.  admin.diff.org.ua. (
                                2015060213 ; Serial
                                8H ; Refresh
                                1H ; Retry
                                1W ; Expire
                                1D ) ; minimum, seconds
;
; DNS Servers
                IN      NS      ns1.diff.org.ua.
                IN      NS      ns2.diff.org.ua.
; MX Records
;;              IN      MX  10  mail.diff.org.ua.
                IN      A       91.100.100.91
; SPF
;               IN      TXT     "v=spf1 +a +mx -all"
;;              IN      TXT     "v=spf1 ip4:91.100.100.91 +mx -all"
; HOST A
ns1             IN      A       91.100.100.91
ns2             IN      A       92.100.100.92
deb             IN      A       91.100.100.91
;;mail          IN      A       91.100.100.91
; CNAME Aliases
www             IN      CNAME   diff.org.ua.

Обязательным условием передачи зоны с master-сервера на slave является увеличение параметра «serial». Не забывайте об этом.

Хай щастить!

    • Григорий
    • Февраль 11th, 2016 6:04пп

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

    • admin
    • Февраль 12th, 2016 1:49пп

    @Григорий
    отличия deb7 vs deb8 минимальны. systemctl вместо service, вот и все отличия что я заметил
    1-й вариант будет кэшировать все что через него пролетает — думаю то что вам нужно.

    • Григорий
    • Февраль 12th, 2016 3:24пп

    тогда интересно, сегодня делал настройку ругался именно расширение school9.local не нравится local и все тут

    • admin
    • Февраль 13th, 2016 2:31пп

    @Григорий
    скопируйте сюда кусок логов там где ругался bind, может дело в другом …

    • Григорий
    • Февраль 13th, 2016 4:34пп

    да уже не могу. переделываю. счас другая проблема..
    named-checkconf -z
    /etc/bind/school.my.zone:3: ignoring out-of-zone data (school.my)
    /etc/bind/school.my.zone:5: ignoring out-of-zone data (gw.school.my)
    zone schoool.my/IN: has 0 SOA records
    zone schoool.my/IN: has no NS records
    zone schoool.my/IN: not loaded due to errors.
    _default/schoool.my/IN: bad zone
    zone localhost/IN: loaded serial 2
    zone 127.in-addr.arpa/IN: loaded serial 1
    zone 0.in-addr.arpa/IN: loaded serial 1
    zone 255.in-addr.arpa/IN: loaded serial 1

    • Григорий
    • Февраль 13th, 2016 4:40пп

    поправил…стало лучше. осталось внести внутренние сервера..

    • shuric
    • Март 19th, 2016 12:15дп

    Master slave -это физически 2 разных сервера?

    • admin
    • Апрель 6th, 2016 8:42дп

    @shuric
    конечно

  1. Трэкбэков пока нет.

Why ask?