README.md

ISC DHCP Web Console

Веб-интерфейс для управления ISC DHCP сервером: просмотр аренд, управление резервациями MAC→IP, история подключений, метки, фоновый ping и статистика устройств.

Аналог DHCP-страницы домашнего роутера, но для self-hosted isc-dhcp-server на Ubuntu / Debian.


Возможности

  • Аренды — таблица всех текущих lease’ов: IP, MAC, hostname, vendor (OUI lookup), статус (active / expired / abandoned), времена начала и окончания. Фильтр по статусу, поиск, сортировка.
  • Резервации (MAC→IP) — добавление и удаление через web UI с применением через OMAPI (live, без рестарта dhcpd) и записью в reservations.conf для персистентности. Кнопка «Закрепить» прямо из строки аренды.
  • Метки — произвольное имя и заметка для любого MAC, отображается в таблицах. Inline-редактирование кликом.
  • История — фоновый поллер каждые 60 секунд снимает срез active-аренд, ведёт таблицу устройств и события (first_seen, ip_change). Авто-pruning старше 90 дней.
  • Фоновый ping — ICMP-проба всех active-аренд раз в 60с, агрегаты в окне 24ч: uptime %, средняя/последняя RTT, всего проб.
  • Wake-on-LAN — кнопка в строке аренды отправляет magic packet.
  • Онлайн-индикатор — зелёная/серая точка слева от IP по содержимому /proc/net/arp.
  • Backup / Restore — экспорт всех резерваций и меток в JSON, импорт в режиме merge или replace.
  • Валидация конфига — перед применением каждой правки запускается dhcpd -t -cf <config>, при ошибке изменение откатывается.

Архитектура

Файл Назначение
app.py Flask приложение, маршруты /api/*
leases.py Парсер /var/lib/dhcp/dhcpd.leases через isc_dhcp_leases
reservations.py Файловое хранилище резерваций (reservations.conf), атомарная запись
omapi_client.py Обёртка над pypureomapi для live-применения резерваций
validator.py Запуск dhcpd -t для валидации конфига перед сохранением
history.py SQLite, таблицы devices и events, фоновый поллер
labels.py Пользовательские метки для MAC, таблица labels
ping.py Фоновый ICMP ping, агрегаты, таблица ping_samples
presence.py Парсер /proc/net/arp для онлайн-индикатора
wol.py Генерация и отправка Wake-on-LAN magic packet
oui.py MAC→vendor через mac-vendor-lookup
mac.py Общая валидация и нормализация MAC-адресов
db.py Общие SQLite helpers (один файл БД на history, labels, ping)
static/ HTML, CSS, JS (без сборки, ванильный JS)
tests/ 228 pytest-тестов
systemd/ Unit-файл и пример env
install.sh Установочный скрипт

Требования

  • Ubuntu 24.04 или совместимый Debian-based дистрибутив
  • isc-dhcp-server установлен и запущен
  • Python 3.12+
  • Для фонового ping: iputils-ping (есть по умолчанию)

Установка (production)

sudo ./install.sh

Скрипт:

  1. Копирует код в /opt/dhcp-web-console
  2. Создаёт venv, ставит зависимости из requirements.txt
  3. Создаёт /var/lib/dhcp-web-console/ под пользователем dhcpd
  4. Устанавливает systemd unit и /etc/default/dhcp-web-console (если не существует)
  5. Делает systemctl daemon-reload

После установки:

  1. Добавить в /etc/dhcp/dhcpd.conf строку:

    include "/var/lib/dhcp-web-console/reservations.conf";
    
  2. Перезапустить dhcpd: sudo systemctl restart isc-dhcp-server
  3. Запустить веб-консоль: sudo systemctl enable --now dhcp-web-console
  4. Открыть http://<host>:9990/

Опционально: OMAPI для live-применения резерваций

  1. Сгенерировать ключ:

    tsig-keygen -a HMAC-MD5 omapi_key
    
  2. Добавить в /etc/dhcp/dhcpd.conf (использовав вывод выше):

    key omapi_key {
     algorithm hmac-md5;
     secret "<BASE64_СЕКРЕТ_ИЗ_ВЫВОДА>";
    }
    omapi-port 7911;
    omapi-key omapi_key;
    
  3. Раскомментировать в /etc/default/dhcp-web-console:

    DHCP_OMAPI_KEY_NAME=omapi_key
    DHCP_OMAPI_KEY_SECRET=<BASE64_СЕКРЕТ>
    
  4. sudo systemctl restart isc-dhcp-server dhcp-web-console

Без этой настройки резервации всё равно работают, но через systemctl reload isc-dhcp-server (или после перезапуска сервиса).


Конфигурация (env vars)

Все переменные опциональны. Указаны значения по умолчанию.

Переменная Default Назначение
HOST 0.0.0.0 Адрес для bind
PORT 9990 Порт
DEBUG (unset) Если задан — Flask в debug-режиме
Файлы
DHCP_LEASES_FILE /var/lib/dhcp/dhcpd.leases Где читать leases
DHCP_RESERVATIONS_FILE /etc/dhcp/reservations.conf Куда писать резервации
DHCP_CONFIG_FILE /etc/dhcp/dhcpd.conf Для валидации dhcpd -t
DHCPD_BIN /usr/sbin/dhcpd Бинарь dhcpd
DHCP_HISTORY_DB /var/lib/dhcp-web-console/history.db SQLite файл
OMAPI
DHCP_OMAPI_HOST 127.0.0.1
DHCP_OMAPI_PORT 7911
DHCP_OMAPI_KEY_NAME (пусто = выключено) Имя ключа из dhcpd.conf
DHCP_OMAPI_KEY_SECRET (пусто = выключено) base64 секрет
DHCP_OMAPI_TIMEOUT 5 Сек
История
DHCP_POLL_INTERVAL 60 Сек
DHCP_HISTORY_RETENTION_DAYS 90 0 = не удалять
Ping
DHCP_PING_ENABLED 1 0 отключает фоновый ping
DHCP_PING_INTERVAL 60 Сек
DHCP_PING_TIMEOUT 1 Сек на одну пробу
DHCP_PING_RETENTION_DAYS 30
DHCP_PING_STATS_HOURS 24 Окно для агрегатов
PING_BIN ping
Presence
PRESENCE_TTL 15 Кэш ARP в секундах
ARP_TABLE_PATH /proc/net/arp
Wake-on-LAN
WOL_BROADCAST 255.255.255.255
WOL_PORT 9
Валидация
DHCP_VALIDATE_TIMEOUT 10 Сек на dhcpd -t

API

Все ответы — JSON. Все MAC принимаются в любом формате (:, -, ., без разделителей), возвращаются в aa:bb:cc:dd:ee:ff.

Аренды

GET  /api/leases?state=all|active|expired|abandoned

Возвращает массив объектов: ip, mac, hostname, vendor, start, end, state, binding_state, label, note, online.

Резервации

GET    /api/reservations
POST   /api/reservations              {name, mac, ip, comment?}
DELETE /api/reservations/<mac>

POST возвращает 201 + объект; 400 при ошибке валидации, 502 при сбое OMAPI (с откатом файла).

Метки

GET    /api/labels
PUT    /api/labels/<mac>              {name, note?}
DELETE /api/labels/<mac>

История

GET /api/history/devices?limit=500
GET /api/history/events?limit=200&mac=<mac>

Ping

GET /api/ping/stats

Per-IP: total, success, uptime, avg_rtt_ms, last_rtt_ms, last_success, last_ts, mac, hostname, label.

Wake-on-LAN

POST /api/wol/<mac>

Backup / Restore

GET  /api/backup
POST /api/restore?mode=replace|merge

Body restore: {"version": 1, "reservations": [...], "labels": [...]}. Ответ содержит счётчики reservations_added/skipped, labels_added/skipped.

Health

GET /api/health   → {"ok": true}

Разработка

git clone <repo>
cd isc_dhcp_web_console
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements-dev.txt
pytest

Локальный запуск (без записи в системные файлы):

DHCP_LEASES_FILE=tests/fixtures/sample.leases \
DHCP_RESERVATIONS_FILE=/tmp/res.conf \
DHCP_HISTORY_DB=/tmp/history.db \
DHCP_PING_ENABLED=0 \
PORT=19990 HOST=127.0.0.1 \
.venv/bin/python app.py

Открыть http://127.0.0.1:19990/.

Тесты

228 тестов в tests/, ~16 секунд на полный прогон. Все модули покрыты unit-тестами + API endpoint тесты с Flask test client.

.venv/bin/pytest               # все
.venv/bin/pytest tests/test_leases.py -v

Troubleshooting

Ping показывает 100% packet loss для всех устройств. Под systemd с NoNewPrivileges=true setuid не работает. Юнит уже содержит AmbientCapabilities=CAP_NET_RAW. Если ping всё равно не работает, проверьте:

systemctl cat dhcp-web-console | grep -i cap

Если capability нет — пересоздайте юнит из репозитория.

OMAPI пишет connection failed: [Errno 111]. 1. Убедитесь что в dhcpd.conf есть блок key и omapi-port 7911; 2. Проверьте порт: ss -tlnp | grep 7911 3. Проверьте имя ключа и secret в /etc/default/dhcp-web-console совпадают с dhcpd.conf 4. Рестарт: systemctl restart isc-dhcp-server dhcp-web-console

Аренды не отображаются. Сервис запущен от пользователя dhcpd, ему нужен доступ на чтение /var/lib/dhcp/dhcpd.leases. По умолчанию права 0644, проблем быть не должно. Проверьте:

sudo -u dhcpd cat /var/lib/dhcp/dhcpd.leases | head

OUI vendor пуст для всех устройств. При первом запуске mac-vendor-lookup скачивает базу с IEEE. Если нет интернета — vendor будет пустым. Принудительное обновление:

/opt/dhcp-web-console/.venv/bin/python -c "from mac_vendor_lookup import MacLookup; MacLookup().update_vendors()"

Резервация добавилась, но dhcpd её не видит. Если OMAPI не настроен — нужен systemctl reload isc-dhcp-server после каждой правки. Включите OMAPI (см. выше) — изменения станут мгновенными.

Очистить историю.

sudo rm /var/lib/dhcp-web-console/history.db
sudo systemctl restart dhcp-web-console

Безопасность

Авторизации нет — приложение рассчитано на доверенную локальную сеть. Не публикуйте порт 9990 наружу. Если нужно — поставьте nginx с basic auth и/или TLS перед ним.

Описание
Веб-интерфейс для управления ISC DHCP сервером: просмотр аренд, управление резервациями MAC→IP, история подключений, метки, фоновый ping и статистика устройств.
Конвейеры
0 успешных
0 с ошибкой
Разработчики