Сторонние сервисы в веб-интерфейсе Wiren Board
Это черновик страницы. Последняя правка сделана 10.08.2026 пользователем D.Nikolaev.
Описание
Доступно в релизе testing
На контроллер часто устанавливают сторонние сервисы с собственным веб-интерфейсом: Node-RED, Grafana, zigbee2mqtt и другие. После установки можно столкнуться со следующими проблемами:
- Отсутствие защиты — сторонний софт работает на отдельном порту и по умолчанию открыт для любого, у кого есть доступ к контроллеру по сети.
- Сложная навигация — если у вас несколько контроллеров, трудно держать в голове, какие именно сервисы установлены на каждом контроллере и на каких портах работает каждый сервис. Но даже если вы всё помните, адрес приложения каждый раз приходится вводить в строку браузера вручную.
Веб-интерфейс контроллера решает обе проблемы. Вы можете использовать эти решения по отдельности или вместе:
- Авторизация (Безопасность) — закрывает доступ к приложению паролем от контроллера. Войти смогут только пользователи с нужным уровнем прав.
- Ссылка в меню (Удобство) — добавляет ссылку на приложение в боковое меню веб-интерфейса. Сервис откроется в новой вкладке браузера — вам больше не придётся вручную вводить его IP-адрес и порт.
Что выбрать
«Гейт» (от английского gate — ворота, шлюз) — это правило встроенного веб-сервера контроллера, которое стоит на входе к сервису и пропускает к нему только пользователей, вошедших в веб-интерфейс. Настройка описывается двумя видами JSON-файлов, у каждого своя задача:
- Файл гейта (
gates.d) отвечает за сеть и авторизацию: на каком порту принимать запросы, кого пускать, работать ли по HTTPS. - Файл меню (
custom-menu) отвечает только за навигацию: добавляет ссылку в боковое меню, ничего не защищает.
Если в файле гейта указать раздел menu, гейт сам добавит пункт в меню — под капотом он создаёт запись в том же формате, что и файл меню. Отдельно описывать пункт не нужно. Обратное неверно: файл меню сам по себе гейт не создаёт.
Отсюда три сценария:
| Что нужно | Что сделать |
|---|---|
| Просто ссылка в меню, без авторизации (сервис защищён сам или работает на другом устройстве) | Только файл меню |
| Закрыть сервис авторизацией и сразу показать пункт в меню | Файл гейта с разделом menu
|
| Закрыть сервис авторизацией, без пункта в меню | Файл гейта без раздела menu — при желании пункт можно добавить отдельным файлом меню со ссылкой /open-<имя>
|
Сервис за авторизацией контроллера
В веб-интерфейсе должен быть создан хотя бы один пользователь — иначе защиты не будет. Пока пользователей нет, контроллер открывается с правами администратора без запроса входа, и гейт пропустит любого. Создайте пользователей в разделе Аутентификация и авторизация пользователя.
Сам сервис слушает только внутренний адрес 127.0.0.1 и снаружи недоступен, а гейт принимает соединения на отдельном внешнем порту и проверяет каждый запрос:
- пользователя без активного входа браузер перенаправит на форму входа веб-интерфейса, а после входа вернёт обратно к сервису;
- запрос от программы или скрипта без входа получит ответ 401;
- если в настройках контроллера включён HTTPS — гейт тоже работает по HTTPS, отдельно настраивать ничего не нужно.
Настройка
Команды выполняются на контроллере — например, по SSH под пользователем root.
- Настройте сервис так, чтобы он слушал только адрес 127.0.0.1 — иначе внутренний порт останется доступен снаружи в обход авторизации. Как это сделать смотрите в документации на соответствующий сервис.
- Откройте новый файл гейта в редакторе. Имя файла — строчные латинские буквы, цифры и дефис, расширение
.json; в примере этоmy-service.json:nano /etc/wb-homeui/gates.d/my-service.json
- Вставьте описание гейта и сохраните файл (в nano —
Ctrl+O,Enter, затемCtrl+X):{ "internalPort": 9000, "externalPort": 29000, "role": "admin", "menu": { "title": { "ru": "Мой сервис", "en": "My service" } } }
- Проверьте и примените описание:
wb-homeui-gates check wb-homeui-gates apply
- Команда
checkпоказывает, какие гейты получатся из ваших файлов, а для файлов с ошибками — причину. Командаapplyсоздаёт настройки веб-сервера и перезапускает его. Если новая конфигурация оказалась неработоспособной,applyпечатает причину и возвращает веб-сервер к прежнему состоянию — сломать веб-интерфейс или соседние гейты не получится. Поправьте файл и запуститеapplyещё раз.
Поля файла описания:
| Поле | Обязательное | Что задаёт |
|---|---|---|
externalPort |
да | Внешний порт гейта, от 1024 до 65535. Не должен совпадать с портами других гейтов и их сервисов. |
internalPort |
да | Порт сервиса на 127.0.0.1, тоже от 1024 до 65535. |
role |
нет, по умолчанию admin |
Минимальный уровень доступа: user, operator или admin. Пускает пользователей с этим уровнем и выше; user пускает любого вошедшего.
|
auth |
нет, по умолчанию true |
false — пускать на сервис без авторизации.
|
menu |
нет | Пункт в разделе меню «Интеграции». menu.title — подписи на русском и английском, достаточно одной. Пользователям с уровнем ниже role пункт не показывается.
|
Каталог /etc/wb-homeui сохраняется при обновлении прошивки контроллера. Перенос в защищённый от обновлений раздел завершается после перезагрузки — после первой настройки перезагрузите контроллер.
Как открыть сервис
- Через пункт меню — если в описании гейта задано поле
menu. - По адресу
http://<адрес контроллера>/open-<имя>, где имя — имя JSON-файла без расширения: контроллер перенаправит вас на порт гейта.
Открывайте сервис по тому же адресу — IP или доменному имени, — по которому открываете веб-интерфейс. Если зайти на порт гейта по другому адресу, вход не сработает: браузер будет бесконечно возвращать вас на форму входа.
Свои настройки веб-сервера
Если гейту нужны нестандартные настройки nginx — увеличенные таймауты, дополнительные location — создайте рядом с JSON-файлом файл <имя>.nginx.inc: его содержимое попадёт внутрь server-блока гейта. Ошибку в таком файле поймает проверка при apply: применение откатится, ваш файл останется на месте — поправьте его и повторите команду.
Ссылка на сервис в меню
Этот способ добавляет в боковое меню ссылку — на сервис за гейтом (адрес /open-<имя>), на сервис со своей авторизацией или на сервис на другом устройстве. Сам по себе он ничего не защищает. Файлы создаются в каталоге /etc/wb-homeui/custom-menu/, команды выполняются на контроллере под root.
Куда попадёт пункт, зависит от его поля id:
- новый
id— пункт добавляется отдельной строкой в конец бокового меню; idсовпадает с существующим разделом (например,integrations— раздел «Интеграции») — пункт вливается в этот раздел;- пункт с
childrenстановится раскрывающимся разделом со вложенными ссылками.
Это ваш контроллер — класть пункт можно куда угодно. Откройте новый файл (имя любое) в редакторе:
nano /etc/wb-homeui/custom-menu/my-service.json
Вставьте один из вариантов ниже и сохраните файл (в nano — Ctrl+O, Enter, затем Ctrl+X). Изменения видны после обновления страницы веб-интерфейса.
Адрес в url лучше делать относительным: /open-<имя> для сервиса за гейтом или путь от корня (/…) — такая ссылка следует за адресом контроллера и не сломается при смене IP или доменного имени. Полный адрес http://<IP>:<порт> нужен только для сервиса на другом устройстве; при смене того адреса ссылку придётся править вручную.
Вариант 1. В раздел «Интеграции» (рекомендуется). Ссылка на сервис, закрытый гейтом на этом контроллере: адрес /open-<имя> не привязан к IP. Обёртка с id: "integrations" и списком children кладёт пункт в тот же раздел, что и гейт.
[
{
"id": "integrations",
"children": [
{
"id": "my-service",
"title": { "ru": "Мой сервис", "en": "My service" },
"url": "/open-my-service",
"isExternal": true,
"openInNewTab": true
}
]
}
]
Вариант 2. Свой раздел. Новый id с children создаёт отдельный раскрывающийся раздел (сам раздел ссылкой не является, поэтому url у него не нужен). В children добавьте столько пунктов, сколько нужно; здесь для примера — сервис на другом устройстве, поэтому указан полный адрес.
[
{
"id": "my-services",
"title": { "ru": "Мои сервисы", "en": "My services" },
"children": [
{
"id": "svc-1",
"title": { "ru": "Сервис 1", "en": "Service 1" },
"url": "http://192.168.1.50:8081",
"isExternal": true,
"openInNewTab": true
},
{
"id": "svc-2",
"title": { "ru": "Сервис 2", "en": "Service 2" },
"url": "http://192.168.1.50:8082",
"isExternal": true,
"openInNewTab": true
}
]
}
]
Вариант 3. Отдельный пункт верхнего уровня. Пункт с новым id и адресом, без обёртки и children, встанет отдельной строкой в конце меню (в примере — внешний сервис с полным адресом).
[
{
"id": "my-service",
"title": { "ru": "Мой сервис", "en": "My service" },
"url": "http://192.168.1.50:8080",
"isExternal": true,
"openInNewTab": true,
"requiredRole": "operator"
}
]
Поля пункта меню:
| Поле | Обязательное | Что задаёт |
|---|---|---|
id |
да | Идентификатор пункта. Если совпадает с идентификатором существующего пункта меню, ваши поля дополняют его — так можно, например, добавить вложенный пункт в штатный раздел. Новые пункты добавляются в конец меню. |
url |
да, для нового пункта | Адрес ссылки. Без isExternal — внутренний путь веб-интерфейса. С isExternal — либо путь от корня (/open-<имя>, /…), который следует за адресом контроллера, либо полный адрес http(s)://… для сервиса на другом устройстве.
|
title |
нет | Подписи на русском и английском, достаточно одной. Без поля подписью станет id.
|
isExternal |
нет | true — ссылка ведёт за пределы веб-интерфейса и открывается как обычная страница. Если адрес не подходит под требования выше, признак не действует.
|
openInNewTab |
нет | Вместе с isExternal: открывать ссылку в новой вкладке.
|
requiredRole |
нет | Минимальный уровень доступа, при котором пункт виден: user, operator или admin. Без поля пункт видят все.
|
children |
нет | Список вложенных пунктов с такой же структурой. |
Поле requiredRole управляет только видимостью пункта меню. Права доступа должен проверять сам сервис — или гейт, если ссылка ведёт на него.
Особенности и ограничения
- Облачный сервис Wiren Board пробрасывает на контроллер только основной веб-порт, поэтому гейты работают в локальной сети или при прямом доступе к контроллеру.
- Скрипты и программы должны сначала войти: отправить запрос
POST /auth/loginс именем и паролем, а затем передавать полученный cookieidв каждом запросе. Без него гейт вернет 401. - Если внешний порт гейта уже занят другой программой, проверка при
applyэтого не заметит. Если гейт не отвечает — посмотрите занятые порты командойss -ltnи журнал веб-сервера. - Запросы через гейт ограничены по частоте: 15 запросов в секунду с одного IP-адреса со всплесками до 200. При устойчивом превышении гейт отвечает 429. Обычному веб-интерфейсу за гейтом этого хватает с запасом.