Inicio rápido
Tras la instalación el broker escucha en tres puertos: :1883 para MQTT sobre TCP, :8883 para MQTT sobre TLS y :8567 para el panel web y MQTT sobre WebSocket en la ruta /mqtt.
Abra http://localhost:8567 e inicie sesión como administrador. El acceso por defecto es admin / admin; cambie la contraseña en la sección Perfil justo después del primer inicio de sesión.
Cree su primer usuario: un nombre, una contraseña de al menos ocho caracteres y una regla ACL. La regla $u/# da a un dispositivo acceso completo a su propia rama; el panel incluye un botón «Rama propia» justo para esto.
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
Instalación en Linux
La vía recomendada es el repositorio APT: las actualizaciones llegan con las del sistema.
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
El paquete instala el binario en /opt/elxmqttbroker, crea un usuario del sistema elxmqtt sin acceso interactivo, coloca al lado los datos y config.json (modo 0600) y activa el servicio elxmqttbroker en el arranque.
systemctl status elxmqttbroker # estado
sudo systemctl restart elxmqttbroker # reinicio
journalctl -u elxmqttbroker -f # registros
La unidad está restringida con ProtectSystem=strict: solo el directorio propio del broker admite escritura. Por defecto el panel escucha en 127.0.0.1:8567 y se publica a través de nginx, mientras que los puertos MQTT 1883 y 8883 quedan expuestos directamente: son otro protocolo y no necesitan intermediario.
Upgrade y Connection y fijar un proxy_read_timeout generoso: /ws/live y /mqtt son conexiones WebSocket de larga duración.Instalación en Windows
La vía habitual es el instalador elxmqttbroker-setup.exe: coloca el programa en Program Files, los datos en C:\ProgramData\ELX MQTT Broker, registra opcionalmente el servicio ELXMQTTBroker para que arranque con el sistema y abre los puertos 1883, 8883 y 8567 en el cortafuegos. Habla ruso e inglés y requiere permisos de administrador.
ProgramData y no junto al programa: el broker reescribe config.json desde el panel, y un servicio no debe escribir en Program Files. Al desinstalar, esa carpeta permanece: contiene los usuarios, sus permisos y los mensajes.La vía portable es un único elxmqttbroker.exe: colóquelo en su propia carpeta y ejecútelo, y al lado aparecerán config.json, un directorio data y un certificado TLS autofirmado.
elxmqttbroker.exe # ejecutar con los valores por defecto
elxmqttbroker.exe -web :9000 # panel en otro puerto
elxmqttbroker.exe -version # versión y sello de compilación
Una copia portable puede manejarse como servicio a mano, con las mismas órdenes que usa el instalador:
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
Configuración
config.json es el único archivo que lee el broker. Se crea en el primer arranque y contiene solo lo que debe conocerse antes de iniciar: direcciones, TLS y la cuenta del administrador.
{
"dataDir": "data",
"auth": { "username": "admin", "password": "admin" },
"mqtt": { "tcp": ":1883", "tls": ":8883" },
"web": { "addr": ":8567", "tlsAddr": "" },
"tls": { "cert": "", "key": "", "selfSigned": true,
"hosts": ["localhost", "127.0.0.1", "::1"] },
"logLevel": "info",
"logFormat": "text",
"persistence": true
}
Una password en claro se convierte en passwordHash en el primer arranque y se borra del archivo. Todo lo demás —límites del protocolo, SMTP, puentes, reglas, tokens de API, usuarios MQTT— se configura en el panel y vive en data/users.json; nada de ello exige reiniciar.
Las opciones de línea de órdenes prevalecen sobre el archivo:
| Opción | Qué establece |
|---|---|
| -config | ruta de config.json |
| -data | directorio de datos |
| -mqtt | dirección de MQTT sobre TCP |
| -mqtt-tls | dirección de MQTT sobre TLS |
| -web | dirección del panel web |
| -log | nivel de registro |
| -version | mostrar la versión y salir |
config.json contiene el resumen de la contraseña del administrador, la contraseña de SMTP y las credenciales de la fuente de autenticación externa. El archivo debería tener modo 0600.Usuarios y permisos
Hay dos circuitos y no conviene confundirlos. El administrador es una única cuenta definida en config.json que gestiona solo el panel: sin roles, sin registro, y una vez dentro se tiene acceso completo. Los dispositivos MQTT son una lista de cuentas aparte: un nombre de 1 a 64 caracteres, una contraseña, un indicador de activación y permisos por topic.
Una regla ACL se compone de un filtro de topic, un modo de acceso y una decisión:
| Campo | Valores |
|---|---|
| Filtro | un filtro MQTT corriente: sensors/+/temp, dev/#, $u/# |
| Acceso | read, write o readwrite |
| Decisión | permitir o denegar |
Las reglas se comprueban de arriba abajo, gana la primera coincidencia y todo se deniega por defecto: sin un permiso explícito no hay acceso. El orden forma parte de la configuración, así que las reglas se arrastran con el ratón o se mueven con las flechas.
El filtro expande $u, el nombre del cliente que se conecta. Una sola regla $u/# confina cada dispositivo a su propia rama y le ahorra una regla por nombre.
Las contraseñas se guardan como PBKDF2-HMAC-SHA256 con 210 000 iteraciones y sal aleatoria. Los tokens de sesión y de API se guardan solo como resumen.
Autenticación MQTT
La fuente de credenciales se elige en Ajustes → Autenticación, y solo hay una activa a la vez. El cambio se hace en caliente: primero se comprueba la nueva fuente con el botón Probar y solo si responde el broker conmuta y desconecta a los clientes para que cada uno vuelva a autenticarse. Si la fuente no está accesible, no cambia nada.
| Fuente | Cuándo encaja |
|---|---|
internal | las cuentas se gestionan en el panel; es la opción por defecto |
mysql / mariadb | los dispositivos ya viven en la base de datos de su sistema |
sqlite | lo mismo, pero la base de datos es un archivo |
csv | una lista sencilla; los archivos se recargan cuando cambian |
jwt | el dispositivo presenta un token firmado en lugar de una contraseña |
http | su servicio decide en cada conexión |
El esquema de MySQL y MariaDB sigue al de 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} y ${clientid} se enlazan como parámetros de la consulta en lugar de concatenarse, así que la inyección es imposible. passwordHash admite plain, sha256, sha512, bcrypt y pbkdf2.
Un JWT va en el campo de contraseña o de usuario. Se admiten HS256/384/512 y RS256/384/512; se verifican la firma, exp y nbf, y opcionalmente iss, aud y las reclamaciones propias que quiera. Los permisos vienen de la reclamación acl en cualquiera de los dos formatos de EMQX, y is_superuser exime por completo de la comprobación.
"alg": "none" no pasa.La fuente HTTP recibe {username, password, clientid, peerhost} y responde con {"result": "allow", "acl": […]}. Un 200 vacío cuenta como permiso; deny, 401, 403, un tiempo agotado y cualquier error son un rechazo: un servicio de autorización inaccesible no debe convertirse en una puerta abierta. Las respuestas se guardan en caché durante cacheSeconds.
Reglas: reescritura, suscripción automática, límites
La reescritura de topics sustituye un nombre de topic sobre la marcha. Una regla es un filtro MQTT para una preselección barata, una expresión regular y una plantilla de destino con los grupos $1…$9:
| Cuándo | Filtro | Expresión | Nuevo topic |
|---|---|---|---|
| Siempre | raw/# | ^raw/(.+)$ | cooked/$1 |
El orden sigue a EMQX: primero la reescritura y después la comprobación de ACL, de modo que los permisos se verifican sobre el topic por el que el mensaje viajará realmente. UNSUBSCRIBE pasa por la misma reescritura que SUBSCRIBE; de lo contrario un cliente nunca podría darse de baja.
La suscripción automática crea suscripciones nada más establecerse la conexión, sin SUBSCRIBE por parte del cliente. Una regla %c/# o %u/# da a cada cliente su propia rama sin configuración manual.
Los límites por topic sirven cuando un cliente se comporta bien en conjunto pero un topic concreto llega con demasiada frecuencia:
| Campo | Qué establece |
|---|---|
| Patrón de topic | un filtro MQTT corriente: sensors/+/temp |
| Acción | reducir a un ritmo o descartar por completo |
| Mensajes por segundo | el ritmo objetivo; se admiten fracciones (0.2 es uno cada cinco segundos) |
| Contar por | cliente y topic, o el topic en conjunto |
El control de avalancha se configura en Ajustes → Broker y se aplica por conexión: mensajes por segundo, ráfaga de mensajes, bytes por segundo y ráfaga de bytes. Cero significa sin límite. Excederlo no corta la conexión: el broker hace una pausa antes de la siguiente lectura del socket, TCP cierra la ventana y el emisor se frena solo.
Publicación diferida
Una publicación en $delayed/{segundos}/{topic} la retiene el broker y la entrega a los suscriptores cuando vence. El formato es compatible con EMQX.
mosquitto_pub -t '$delayed/60/sensors/alarm' -m 'dentro de un minuto'
El intervalo va de un segundo a 4 294 967 (unos 49 días). La confirmación llega enseguida: el broker responde de la recepción, no de la existencia de suscriptores. La resolución es de un segundo.
La cola se ve en Reglas → Diferidos: topic, carga útil, cuenta atrás y cancelación de uno en uno o de todos a la vez. Los mensajes sobreviven a un reinicio, y los que vencieron mientras el broker estaba parado salen justo después del arranque.
Puente entre brokers
El broker puede conectarse como cliente a otro broker MQTT y reenviar topics en ambos sentidos. Se configura en Ajustes → Puentes: la dirección remota (el puerto es opcional: 1883 por defecto, 8883 con TLS), las credenciales, TLS, la versión del protocolo y las reglas.
| Campo de la regla | Significado |
|---|---|
| Filtro | qué topics se reenvían |
| Sentido | out, in o both |
| QoS | calidad de entrega a través del puente |
| Prefijos | qué se antepone en cada lado |
Hay protección contra bucles, reconexión automática, No Local en la versión 5 (sin eco ni duplicados) y estado y contadores en el panel. El puente trabaja a nivel de broker y no como un cliente aparte.
API REST
El panel llama a su propia API con una cookie de sesión; los sistemas externos usan tokens bearer de Ajustes → API. Un token se muestra una sola vez y solo se guarda su resumen. Un token puede emitirse de solo lectura: entonces únicamente pasan GET, HEAD y OPTIONS.
curl -H "Authorization: Bearer TOKEN" http://localhost:8567/api/stats
El caso típico es que su sistema dé de alta un dispositivo y le conceda acceso al broker en el mismo paso:
# crear
curl -X POST http://localhost:8567/api/users \
-H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" \
-d '{"username":"sensor-42","password":"s3nsorPass!","enabled":true,
"acl":[{"filter":"$u/#","access":"readwrite","allow":true}]}'
# cambiar la contraseña o los permisos (solo los campos enviados)
curl -X PATCH http://localhost:8567/api/users/sensor-42 \
-H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" \
-d '{"password":"newPass12345","enabled":false}'
# eliminar
curl -X DELETE http://localhost:8567/api/users/sensor-42 \
-H "Authorization: Bearer TOKEN"
La contraseña nunca se devuelve. Los errores llegan con una forma única, {"error":{"code":"…","message":"…"}}: duplicate, reserved, invalid_input, not_found, read_only, unauthorized.
Los cambios se aplican al instante: al cambiar una contraseña, unos permisos o al eliminar, el broker corta él mismo las conexiones activas de ese usuario, de modo que las nuevas reglas surten efecto de inmediato y no en la siguiente reconexión.
Está disponible toda la API del panel: estadísticas e historial, clientes, suscripciones, mensajes retenidos, publicación, eventos, usuarios, ajustes, puentes, reglas, mensajes diferidos, importación y exportación.
Almacenamiento y reinicios
Con persistence: true el estado vive en data/broker.db: SQLite en modo WAL, Go puro, sin CGO. Qué sobrevive a un reinicio:
- Los mensajes retenidos: se escriben en cuanto cambian, no según un temporizador. Todo lo que haya superado su Message Expiry se descarta en el arranque.
- Las sesiones persistentes: suscripciones, colas sin conexión de QoS 1/2 y negociaciones inacabadas. Se vuelcan cada diez segundos y al apagar. Las sesiones limpias no se guardan: por especificación mueren con la conexión.
- Los mensajes diferidos: los que vencieron mientras el broker estaba parado salen justo después del arranque.
En el arranque va al registro una línea como state restored retained=128 sessions=7 subscriptions=34 delayed=2. Junto a ella, en data/, están users.json (cuentas, reglas y ajustes del panel, escrito de forma atómica) y el certificado autofirmado.
Limitaciones conocidas
- No se admite el clustering: el broker está diseñado como un proceso único.
- El puente habla QoS 0 y 1; el QoS 2 se rebaja a 1.
- La autenticación reforzada del tipo SCRAM existe en el protocolo, pero la fuente interna no la ofrece y responde
0x8C Bad authentication method. - La limitación de ritmo se aplica por conexión y no por usuario: un cliente que abra diez conexiones obtiene diez límites.
- La salud de la máquina se calcula en Linux y Windows; en macOS y BSD la ficha dice honestamente «sin datos».