Быстрый старт
После установки брокер слушает три порта: :1883 — MQTT поверх TCP, :8883 — MQTT поверх TLS, :8080 — веб-панель и MQTT over WebSocket по пути /mqtt.
Откройте http://localhost:8080 и войдите администратором. Логин по умолчанию — admin / admin; смените пароль в разделе «Профиль» сразу после первого входа.
Заведите первого пользователя: имя, пароль от восьми символов и правило ACL. Правило $u/# даёт устройству полный доступ к собственной ветке — в панели для этого есть кнопка «Своя ветка».
mosquitto_pub -h localhost -p 1883 -u sensor-42 -P s3nsorPass! \
-t 'sensor-42/temp' -m '21.5'
mosquitto_sub -h localhost -p 1883 -u sensor-42 -P s3nsorPass! \
-t 'sensor-42/#' -v
Установка на Linux
Рекомендуемый способ — APT-репозиторий: обновления приходят вместе с системными.
sudo wget -qO /usr/share/keyrings/elx-repo.gpg https://repo.um-d.ru/elx-repo.gpg
echo "deb [signed-by=/usr/share/keyrings/elx-repo.gpg] https://repo.um-d.ru stable main" | sudo tee /etc/apt/sources.list.d/elx-repo.list
sudo apt-get update
sudo apt-get install elxmqttbroker
Пакет ставит бинарник в /opt/elxmqttbroker, заводит системного пользователя elxmqtt без права входа, кладёт данные и config.json с правами 0600 рядом и включает службу elxmqttbroker в автозапуск.
systemctl status elxmqttbroker # состояние
sudo systemctl restart elxmqttbroker # перезапуск
journalctl -u elxmqttbroker -f # логи
Юнит закрыт ProtectSystem=strict: писать разрешено только в каталог брокера. Панель по умолчанию слушает 127.0.0.1:8080 и публикуется наружу через nginx, а MQTT-порты 1883 и 8883 открыты напрямую — это отдельный протокол, проксировать его не нужно.
Upgrade и Connection и большой proxy_read_timeout: /ws/live и /mqtt — долгоживущие WebSocket-соединения.Установка на Windows
Обычный путь — установщик elxmqttbroker-setup.exe: он кладёт программу в Program Files, данные в C:\ProgramData\ELX MQTT Broker, по желанию регистрирует службу ELXMQTTBroker с автозапуском и открывает порты 1883, 8883 и 8080 в брандмауэре. Установщик говорит по-русски и по-английски и требует прав администратора.
ProgramData, а не рядом с программой: брокер переписывает config.json сам из панели, а службе нечего писать в Program Files. При удалении эта папка остаётся — в ней пользователи, права и сообщения.Переносимый вариант — один elxmqttbroker.exe: положите его в отдельную папку и запустите, рядом появятся config.json, каталог data и самоподписанный TLS-сертификат.
elxmqttbroker.exe # запуск с настройками по умолчанию
elxmqttbroker.exe -web :9000 # панель на другом порту
elxmqttbroker.exe -version # версия и штамп сборки
Переносимой копией можно управлять как службой и вручную — теми же командами, что использует установщик:
elxmqttbroker.exe -service install -config "C:\ProgramData\ELX MQTT Broker\config.json" -data "C:\ProgramData\ELX MQTT Broker\data"
elxmqttbroker.exe -service start
elxmqttbroker.exe -service stop
elxmqttbroker.exe -service uninstall
Конфигурация
config.json — единственный файл, который читает брокер. Он создаётся при первом запуске и содержит только то, что нужно знать до старта: адреса, TLS и учётку администратора.
{
"dataDir": "data",
"auth": { "username": "admin", "password": "admin" },
"mqtt": { "tcp": ":1883", "tls": ":8883" },
"web": { "addr": ":8080", "tlsAddr": "" },
"tls": { "cert": "", "key": "", "selfSigned": true,
"hosts": ["localhost", "127.0.0.1", "::1"] },
"logLevel": "info",
"logFormat": "text",
"persistence": true
}
Открытый password при первом старте превращается в passwordHash и вычищается из файла. Всё остальное — лимиты протокола, SMTP, мосты, правила, API-токены, MQTT-пользователи — настраивается в панели и живёт в data/users.json; перезапуск для этого не нужен.
Флаги командной строки перекрывают файл:
| Флаг | Что задаёт |
|---|---|
| -config | путь к config.json |
| -data | каталог данных |
| -mqtt | адрес MQTT поверх TCP |
| -mqtt-tls | адрес MQTT поверх TLS |
| -web | адрес веб-панели |
| -log | уровень логирования |
| -version | напечатать версию и выйти |
config.json содержит хеш пароля администратора, пароль SMTP и учётные данные внешнего источника аутентификации. Права на файл должны быть 0600.Пользователи и права
Контуров два, и путать их не стоит. Администратор — один, задаётся в config.json и управляет только панелью: ролей нет, регистрации нет, вошли — значит полный доступ. MQTT-устройства — отдельный список учёток: имя от 1 до 64 символов, пароль, флаг «включён» и права по темам.
ACL-правило состоит из фильтра темы, вида доступа и решения:
| Поле | Значения |
|---|---|
| Фильтр | обычный MQTT-фильтр: sensors/+/temp, dev/#, $u/# |
| Доступ | read, write или readwrite |
| Решение | разрешить или запретить |
Правила проверяются сверху вниз, срабатывает первое подходящее, и всё deny-by-default: без явного разрешения доступа нет. Порядок — часть настройки, поэтому правила перетаскиваются мышью или двигаются стрелками с клавиатуры.
В фильтре разворачивается $u — имя подключившегося клиента. Одно правило $u/# замыкает каждое устройство в собственной ветке и избавляет от правила на каждое имя.
Пароли хранятся как PBKDF2-HMAC-SHA256, 210 000 итераций, со случайной солью. Токены сессий и API хранятся только хешами.
Аутентификация MQTT
Источник учётных записей выбирается в «Настройки → Аутентификация»; активен всегда ровно один. Смена происходит на лету: новый источник сначала проверяется кнопкой «Проверить», и только если он отвечает, брокер переключается и отключает клиентов, чтобы каждый прошёл проверку заново. Если источник недоступен, не меняется ничего.
| Источник | Когда подходит |
|---|---|
internal | учётки ведутся в панели — по умолчанию |
mysql / mariadb | устройства уже живут в базе вашей системы |
sqlite | то же самое, но база — файл |
csv | простой список, файлы перечитываются при изменении |
jwt | устройство предъявляет подписанный токен вместо пароля |
http | решение принимает ваш сервис на каждое подключение |
Схема для MySQL и MariaDB — в стиле EMQX:
CREATE TABLE mqtt_user (username VARCHAR(128) PRIMARY KEY, password VARCHAR(255));
CREATE TABLE mqtt_acl (username VARCHAR(128), action VARCHAR(16),
permission VARCHAR(16), topic VARCHAR(255));
-- action: publish | subscribe | pubsub; permission: allow | deny
INSERT INTO mqtt_user VALUES ('dev', SHA2('devpass',256));
INSERT INTO mqtt_acl VALUES ('dev','pubsub','allow','dev/#');
"mqttAuth": {
"backend": "mariadb",
"sql": {
"dsn": "mqtt:mqttpass@tcp(127.0.0.1:3306)/mqtt",
"passwordQuery": "SELECT password FROM mqtt_user WHERE username = ${username} LIMIT 1",
"aclQuery": "SELECT action, permission, topic FROM mqtt_acl WHERE username = ${username}",
"passwordHash": "sha256"
}
}
${username} и ${clientid} подставляются параметрами запроса, а не склейкой строк — инъекция невозможна. passwordHash принимает plain, sha256, sha512, bcrypt и pbkdf2.
JWT кладётся в поле пароля или логина. Поддерживаются HS256/384/512 и RS256/384/512, проверяются подпись, exp, nbf, при желании iss, aud и любые свои claim'ы. Права берутся из claim acl в любом из двух форматов EMQX, а is_superuser снимает проверку целиком.
"alg": "none" не проходит.HTTP-источник получает {username, password, clientid, peerhost} и отвечает {"result": "allow", "acl": […]}. Пустой 200 тоже считается разрешением; deny, 401, 403, таймаут и любая ошибка — отказ: недоступный сервис авторизации не должен превращаться в открытую дверь. Ответы кэшируются на cacheSeconds.
Правила: перезапись, автоподписка, лимиты
Перезапись тем подменяет имя темы на лету. Правило — это MQTT-фильтр для дешёвого отбора, регулярное выражение и шаблон новой темы с группами $1…$9:
| Когда | Фильтр | Выражение | Новая тема |
|---|---|---|---|
| Всегда | raw/# | ^raw/(.+)$ | cooked/$1 |
Порядок как в EMQX: сначала перезапись, потом проверка ACL — права проверяются на той теме, под которой сообщение реально поедет. UNSUBSCRIBE проходит ту же перезапись, что и SUBSCRIBE, иначе клиент не смог бы отписаться.
Автоподписка оформляет подписки сразу после подключения — SUBSCRIBE от клиента не нужен. Правило %c/# или %u/# даёт каждому клиенту свою ветку без ручной настройки.
Ограничения по темам нужны, когда клиент ведёт себя нормально, а слишком часто идёт одна конкретная тема:
| Поле | Что задаёт |
|---|---|
| Шаблон темы | обычный MQTT-фильтр: sensors/+/temp |
| Действие | прореживать до нормы или игнорировать полностью |
| Сообщений в секунду | норма; дробные значения допустимы (0.2 — одно в пять секунд) |
| Считать | по клиенту и теме или по теме целиком |
Флуд-контроль настраивается в «Настройки → Брокер» и действует на каждое подключение: сообщений в секунду, всплеск сообщений, байт в секунду, всплеск байт. Ноль — ограничения нет. Превышение не рвёт соединение: брокер делает паузу перед следующим чтением из сокета, TCP закрывает окно, и отправитель замедляется сам.
Отложенная публикация
Публикация в тему $delayed/{секунды}/{тема} придерживается брокером и уходит подписчикам, когда срок истечёт. Формат совместим с EMQX.
mosquitto_pub -t '$delayed/60/sensors/alarm' -m 'через минуту'
Интервал — от одной секунды до 4 294 967 (около 49 суток). Подтверждение приходит сразу: брокер отвечает за приём, а не за наличие подписчиков. Точность — одна секунда.
Очередь видна в «Правила → Отложенные»: тема, payload, обратный отсчёт, отмена поштучно или целиком. Сообщения переживают перезапуск, а те, чей срок истёк, пока брокер лежал, уходят сразу при старте.
Мост между брокерами
Брокер умеет подключаться как клиент к другому MQTT-брокеру и пересылать темы в обе стороны. Настраивается в «Настройки → Мосты»: адрес удалённого брокера (порт необязателен — по умолчанию 1883, а по TLS 8883), логин, TLS, версия протокола и правила.
| Поле правила | Значение |
|---|---|
| Фильтр | какие темы пересылать |
| Направление | out, in или both |
| QoS | качество доставки через мост |
| Префиксы | что добавить к теме на той и на этой стороне |
Есть защита от петель, авто-переподключение, No Local на пятой версии (нет эха и дублей), статус и счётчики в панели. Мост работает на уровне брокера, а не отдельного клиента.
REST API
Панель ходит в собственный API по cookie сессии; для внешних систем есть bearer-токены — «Настройки → API». Токен показывается один раз, в базе лежит только его хеш. Токен можно выдать только на чтение — тогда проходят лишь GET, HEAD и OPTIONS.
curl -H "Authorization: Bearer ТОКЕН" http://localhost:8080/api/stats
Типовой сценарий — ваша система заводит устройство и сразу выдаёт ему доступ к брокеру:
# создать
curl -X POST http://localhost:8080/api/users \
-H "Authorization: Bearer ТОКЕН" -H "Content-Type: application/json" \
-d '{"username":"sensor-42","password":"s3nsorPass!","enabled":true,
"acl":[{"filter":"$u/#","access":"readwrite","allow":true}]}'
# изменить пароль или права (только переданные поля)
curl -X PATCH http://localhost:8080/api/users/sensor-42 \
-H "Authorization: Bearer ТОКЕН" -H "Content-Type: application/json" \
-d '{"password":"newPass12345","enabled":false}'
# удалить
curl -X DELETE http://localhost:8080/api/users/sensor-42 \
-H "Authorization: Bearer ТОКЕН"
Пароль обратно не возвращается никогда. Ошибки приходят в едином виде {"error":{"code":"…","message":"…"}}: duplicate, reserved, invalid_input, not_found, read_only, unauthorized.
Изменения применяются мгновенно: при смене пароля, прав или удалении брокер сам разрывает живые соединения этого пользователя, чтобы новые правила действовали сразу, а не с очередного переподключения.
Доступен весь API панели: статистика и история, клиенты, подписки, retain, публикация, события, пользователи, настройки, мосты, правила, отложенные сообщения, импорт и экспорт.
Хранилище и перезапуск
При persistence: true состояние лежит в data/broker.db — SQLite в режиме WAL на чистом Go, без CGO. Перезапуск переживают:
- Retain-сообщения — пишутся сразу при каждом изменении, не по таймеру. При старте просроченные по Message Expiry отбрасываются.
- Постоянные сессии — подписки, оффлайн-очереди QoS 1/2, незавершённые рукопожатия. Снимок раз в десять секунд и при остановке. Чистые сессии не сохраняются: по спецификации они умирают вместе с соединением.
- Отложенные сообщения — те, чей срок наступил, пока брокер был выключен, уходят сразу после старта.
При старте в лог идёт строка вида state restored retained=128 sessions=7 subscriptions=34 delayed=2. Рядом в data/ лежат users.json (учётки, правила и настройки панели, запись атомарная) и самоподписанный сертификат.
Известные ограничения
- Кластеризация не поддерживается: брокер рассчитан на один процесс.
- Мост говорит QoS 0 и 1, QoS 2 понижается до 1.
- Расширенная аутентификация вроде SCRAM в протоколе есть, но встроенный источник её не предлагает и отвечает
0x8C Bad authentication method. - Ограничение частоты действует на подключение, а не на пользователя: клиент, открывший десять соединений, получает десять лимитов.
- Состояние машины считается на Linux и Windows; на macOS и BSD карточка честно пишет «нет данных».