ISC DHCP, который десятилетиями раздавал адреса в миллионах сетей, официально снят с поддержки. На смену ему пришёл Kea, современный DHCP-сервер от того же консорциума ISC. У него JSON-конфигурация, хранение аренд в базе данных (MySQL, PostgreSQL) или в файле, REST API для управления на лету, а встроенная схема высокой доступности позволяет держать пару серверов без сторонних костылей вроде общих дисков и скриптов. В этой статье поднимем Kea на srv-dhcp01 (192.168.10.3) для сети 192.168.10.0/24 домена itpages.lab.local, настроим пул, резервации для серверов и добавим второй экземпляр для отказоустойчивости.

План: ставим пакет, описываем подсеть с пулом и опциями (шлюз, DNS, NTP, домен), делаем резервации по MAC-адресам, проверяем выдачу с клиента, затем собираем пару в режиме hot-standby. Параллельно поговорим о том, как не поймать конфликт адресов и не завалить сеть левым DHCP.

Шаг 1. Установка Kea

В Debian и Ubuntu Kea собран из нескольких пакетов. Сам DHCPv4-сервер, управляющий агент и вспомогательные компоненты ставятся отдельно:

sudo apt install kea-dhcp4-server kea-ctrl-agent kea-common
# RHEL / Rocky: sudo dnf install kea
kea-dhcp4 -V
systemctl status kea-dhcp4-server

Конфигурация лежит в /etc/kea/kea-dhcp4.conf. Это JSON с поддержкой комментариев в стиле C, и любая запятая не там вызовет ошибку запуска, поэтому всегда проверяй файл перед применением:

sudo kea-dhcp4 -t /etc/kea/kea-dhcp4.conf

Флаг -t только проверяет конфигурацию и ничего не запускает. Привыкни делать это перед каждой перезагрузкой сервиса, это секундное дело, которое спасает от простоя.

Шаг 2. Базовая конфигурация: подсеть и пул

Минимально рабочий конфиг содержит интерфейс, хранилище аренд и подсеть. Мы сразу зададим опции, которые клиенты должны получить: шлюз, DNS-сервер из прошлой статьи, NTP и поисковый домен.

{
"Dhcp4": {
  "interfaces-config": {
    "interfaces": [ "eth0" ]
  },
  "control-socket": {
    "socket-type": "unix",
    "socket-name": "/run/kea/kea4-ctrl-socket"
  },
  "lease-database": {
    "type": "memfile",
    "persist": true,
    "name": "/var/lib/kea/kea-leases4.csv",
    "lfc-interval": 3600
  },
  "valid-lifetime": 14400,
  "renew-timer": 7200,
  "rebind-timer": 12600,
  "option-data": [
    { "name": "domain-name", "data": "itpages.lab.local" },
    { "name": "domain-search", "data": "itpages.lab.local" },
    { "name": "domain-name-servers", "data": "192.168.10.2" },
    { "name": "ntp-servers", "data": "192.168.10.10" }
  ],
  "subnet4": [
    {
      "id": 1,
      "subnet": "192.168.10.0/24",
      "pools": [ { "pool": "192.168.10.100 - 192.168.10.199" } ],
      "option-data": [
        { "name": "routers", "data": "192.168.10.1" }
      ]
    }
  ]
}
}

Что важно понять. Пул 192.168.10.100-192.168.10.199 это динамический диапазон. Адреса ниже 100 мы оставляем под статику и резервации: шлюз на .1, DNS на .2, DHCP на .3, srv-linux01 на .10. Так динамические выдачи никогда не пересекутся со статическими адресами. Время аренды 14400 секунд (4 часа) подходит для офисной сети с постоянными клиентами. Для гостевого Wi-Fi, где устройства приходят и уходят, ставь час или меньше, иначе пул быстро исчерпается.

Таймеры renew-timer и rebind-timer обычно равны половине и семи восьмым срока аренды: клиент пытается продлить аренду у выдавшего сервера на половине срока, а на 87,5 процентах рассылает запрос всем серверам. Если эти значения не заданы, Kea рассчитает их сам.

Опция interfaces определяет, на каких интерфейсах сервер слушает запросы. Для запроса от клиентов из той же сети этого достаточно. Если нужно обслуживать другие сети через DHCP-реле, подсети описываются тем же способом, а на маршрутизаторах настраивается ретрансляция на адрес 192.168.10.3. Для relay-подсети нужно ещё указать поле relay с адресом ретранслятора.

Шаг 3. Резервации по MAC-адресам

Резервация гарантирует, что определённое устройство всегда получит один и тот же адрес, при этом само устройство остаётся DHCP-клиентом. Это удобнее ручной статики: адрес, шлюз и DNS меняются в одном месте, на сервере. Добавим резервации в блок подсети:

      "reservations": [
        {
          "hw-address": "52:54:00:aa:bb:01",
          "ip-address": "192.168.10.50",
          "hostname": "printer01.itpages.lab.local"
        },
        {
          "hw-address": "52:54:00:aa:bb:02",
          "ip-address": "192.168.10.51",
          "hostname": "nas01.itpages.lab.local",
          "option-data": [
            { "name": "domain-name-servers", "data": "192.168.10.2" }
          ]
        }
      ],
      "reservations-global": false,
      "reservations-in-subnet": true,
      "reservations-out-of-pool": true

Параметр reservations-out-of-pool со значением true сообщает серверу, что все резервации лежат вне динамического пула. Это ускоряет работу: Kea не проверяет каждый адрес пула на предмет резервации. Поэтому и адреса резервации выбраны в диапазоне .50, вне пула .100-.199. Если нужна резервация внутри пула, поставь false, но имей в виду, что поиск станет медленнее на больших сетях.

Если у тебя десятки резерваций, вынеси их в отдельный JSON-файл через директиву include или храни в базе данных с помощью хук-библиотеки host_cmds. Так их можно добавлять без перезапуска, и ручное редактирование огромного конфига не потребуется. Применить изменения конфигурации без остановки сервиса можно командой через управляющий сокет:

sudo kea-dhcp4 -t /etc/kea/kea-dhcp4.conf && \
  sudo systemctl reload kea-dhcp4-server
sudo systemctl enable --now kea-dhcp4-server

Шаг 4. Проверка выдачи и просмотр аренд

Проверка с клиента. На другой машине в той же сети запрашиваем адрес и смотрим результат. Утилита dhclient в режиме verbose показывает весь обмен DORA (Discover, Offer, Request, Ack):

sudo dhclient -v -r eth0
sudo dhclient -v eth0
ip -br addr show eth0
resolvectl status eth0 | grep -E 'DNS|Domain'

Для NetworkManager достаточно nmcli con up на DHCP-профиль. Ожидаем адрес из пула, шлюз 192.168.10.1, DNS 192.168.10.2 и суффикс поиска itpages.lab.local.

На стороне сервера смотри журнал и файл аренд:

sudo journalctl -u kea-dhcp4-server -f
sudo tail -n 20 /var/lib/kea/kea-leases4.csv
sudo tcpdump -i eth0 -nn -vv 'udp port 67 or udp port 68'

В файле аренд в CSV-виде видны адрес, MAC, время окончания аренды и имя хоста. Если клиент пишет Discover, а в ответ тишина, смотри через tcpdump, доходит ли запрос до сервера: чаще всего проблема в файрволе (нужны UDP 67 и 68), в неверном интерфейсе в interfaces-config или в несоответствии подсети (адрес интерфейса сервера не принадлежит описанной подсети).

sudo ufw allow from 192.168.10.0/24 to any port 67 proto udp
# firewalld: sudo firewall-cmd --permanent --add-service=dhcp && sudo firewall-cmd --reload

Шаг 5. Отказоустойчивость: hot-standby

Падение единственного DHCP-сервера не убивает работающую сеть сразу: клиенты держат аренды, пока не истечёт срок. Но через пару часов начнётся массовая потеря адресов, а новые устройства не подключатся совсем. Поэтому держим второй сервер, например srv-dhcp02 (192.168.10.4). Kea поддерживает два режима: load-balancing (оба обслуживают клиентов, каждый свою половину) и hot-standby (отвечает один, второй готов подхватить). Для лаборатории выбираем hot-standby, он проще и предсказуемее.

Режим включается через хук-библиотеку high_availability. Серверы обмениваются данными по HTTP через управляющий агент. Добавляем в конфиг на srv-dhcp01 такой блок:

  "hooks-libraries": [
    { "library": "/usr/lib/x86_64-linux-gnu/kea/hooks/libdhcp_lease_cmds.so" },
    {
      "library": "/usr/lib/x86_64-linux-gnu/kea/hooks/libdhcp_ha.so",
      "parameters": {
        "high-availability": [ {
          "this-server-name": "srv-dhcp01",
          "mode": "hot-standby",
          "heartbeat-delay": 10000,
          "max-response-delay": 60000,
          "max-ack-delay": 5000,
          "max-unacked-clients": 5,
          "peers": [
            {
              "name": "srv-dhcp01",
              "url": "http://192.168.10.3:8000/",
              "role": "primary"
            },
            {
              "name": "srv-dhcp02",
              "url": "http://192.168.10.4:8000/",
              "role": "standby"
            }
          ]
        } ]
      }
    }
  ],

Конфигурация на втором сервере идентична во всём, кроме строки this-server-name, которая указывает уже на srv-dhcp02. Подсеть, пул и опции должны совпадать буква в букву, иначе после переключения клиенты получат другие параметры. Удобно держать общий файл в системе управления конфигурацией и подставлять в него только имя сервера.

Управляющий агент kea-ctrl-agent настраивается в файле /etc/kea/kea-ctrl-agent.conf на прослушивание адреса сервера и порта 8000. Дальше запускаем агент на обоих хостах и открываем TCP 8000 только между серверами, чтобы чужие хосты не могли управлять DHCP:

sudo systemctl enable --now kea-ctrl-agent kea-dhcp4-server
sudo ufw allow from 192.168.10.4 to any port 8000 proto tcp
curl -s -X POST -H 'Content-Type: application/json' \
  -d '{"command":"ha-heartbeat","service":["dhcp4"]}' http://192.168.10.3:8000/

В ответе на heartbeat должно быть состояние сервера: hot-standby у основного и hot-standby у резервного. Проверка сбоя делается просто: останови основной сервис и убедись, что клиентский запрос обслужил второй сервер.

sudo systemctl stop kea-dhcp4-server    # на srv-dhcp01
sudo dhclient -v -r eth0 && sudo dhclient -v eth0   # на клиенте
sudo journalctl -u kea-dhcp4-server | grep -i 'ha-'

В журнале резервного сервера должна появиться запись о переходе в состояние partner-down. Не забудь вернуть основной сервер и убедиться, что пара синхронизировала аренды и вернулась в нормальное состояние.

Отдельно про конфликты адресов. На случай если кто-то назначил статический адрес из пула, включи защиту: в Kea есть хук ping-check, а клиенты могут сами проверять адрес через ARP. Лучше предотвращать проблему организационно: держи таблицу адресации, статику выделяй строго вне пула, а новые серверы сразу заводи в резервации.

Шаг 6. Динамическое обновление DNS и эксплуатация

Резервации хороши для постоянных хостов, но у обычных клиентов имена меняются каждый раз, когда меняется адрес. Чтобы записи в зоне itpages.lab.local обновлялись сами, Kea использует отдельный демон kea-dhcp-ddns, который отправляет в BIND динамические обновления. Для этого в зоне BIND разрешаем обновления от DDNS-демона по ключу TSIG:

zone "itpages.lab.local" {
    type master;
    file "/var/lib/bind/db.itpages.lab.local";
    allow-update { key kea-ddns; };
};

А в конфигурации DHCP-сервера включаем отправку запросов на обновление:

  "dhcp-ddns": {
    "enable-updates": true,
    "server-ip": "127.0.0.1",
    "server-port": 53001
  },
  "ddns-send-updates": true,
  "ddns-override-client-update": true,
  "ddns-qualifying-suffix": "itpages.lab.local",

Имена клиентов появятся в DNS в течение секунд после выдачи аренды, а при её истечении записи будут удалены. Обратите внимание: ключ TSIG должен быть секретным, храни его в файле с правами 640 и никогда не публикуй в репозитории.

Для повседневной эксплуатации пригодится управляющий API. Через него можно посмотреть статистику и состояние пула без чтения логов:

curl -s -X POST -H 'Content-Type: application/json'   -d '{"command":"statistic-get","service":["dhcp4"],"arguments":{"name":"subnet[1].assigned-addresses"}}'   http://192.168.10.3:8000/
curl -s -X POST -H 'Content-Type: application/json'   -d '{"command":"lease4-get-all","service":["dhcp4"]}' http://192.168.10.3:8000/

Если доля занятых адресов приближается к 80 процентам пула, пора расширять диапазон или уменьшать срок аренды. Эту метрику стоит завести в мониторинг заранее. Не забывай и о резервном копировании: достаточно сохранять конфигурацию и файл аренд, а восстановление сводится к копированию их на новый хост и запуску сервиса.

Частые ошибки и как их избежать

  • Два DHCP-сервера в одной сети без согласования. Старый роутер, точка доступа или чужой тестовый сервер раздают свои адреса, и часть клиентов получает неверный шлюз и DNS. Ищи нелегальных раздатчиков командой sudo nmap --script broadcast-dhcp-discover -e eth0 и включай DHCP snooping на управляемых коммутаторах. Два сервера Kea допустимы только как HA-пара.
  • Рассинхронизация конфигов в HA-паре и закрытый порт 8000. Когда подсети или пулы на серверах различаются, после отказа клиенты получают другие параметры, а при закрытом TCP 8000 серверы не видят друг друга и оба начинают отвечать. Держи один шаблон конфига, проверяй kea-dhcp4 -t на обоих хостах и открывай порт управления строго между ними.
  • Пересечение пула с резервациями и статикой, слишком длинная аренда. Адрес из пула уже занят статическим хостом, получаем конфликты и таинственные обрывы. Или аренда в сутки при тысяче временных устройств, и пул исчерпан. Выделяй статику и резервации за пределами пула, включай reservations-out-of-pool и подбирай срок аренды под тип сети: час для гостевой, несколько часов для офиса.

Что дальше

Администрирование Linux — это набор связанных навыков, вот соседние темы серии: