Documentación

Todo lo necesario para poner en marcha y configurar el broker. La ayuda integrada del panel refleja estas secciones y está traducida a siete idiomas.

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.

El administrador del panel no es una cuenta MQTT. Los dispositivos se conectan con cuentas aparte creadas en la sección Usuarios.

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.

La configuración de nginx debe transmitir las cabeceras 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.

Los ajustes viven en 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ónQué establece
-configruta de config.json
-datadirectorio de datos
-mqttdirección de MQTT sobre TCP
-mqtt-tlsdirección de MQTT sobre TLS
-webdirección del panel web
-lognivel de registro
-versionmostrar 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:

CampoValores
Filtroun filtro MQTT corriente: sensors/+/temp, dev/#, $u/#
Accesoread, write o readwrite
Decisiónpermitir 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.

FuenteCuándo encaja
internallas cuentas se gestionan en el panel; es la opción por defecto
mysql / mariadblos dispositivos ya viven en la base de datos de su sistema
sqlitelo mismo, pero la base de datos es un archivo
csvuna lista sencilla; los archivos se recargan cuando cambian
jwtel dispositivo presenta un token firmado en lugar de una contraseña
httpsu 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.

El algoritmo de firma se toma solo de la configuración, nunca de la cabecera del token: una falsificación con "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ándoFiltroExpresiónNuevo topic
Siempreraw/#^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:

CampoQué establece
Patrón de topicun filtro MQTT corriente: sensors/+/temp
Acciónreducir a un ritmo o descartar por completo
Mensajes por segundoel ritmo objetivo; se admiten fracciones (0.2 es uno cada cinco segundos)
Contar porcliente y topic, o el topic en conjunto
La reducción conserva el último valor: un mensaje que llega antes de tiempo se retiene, el siguiente lo sustituye y en el siguiente tic sale el más reciente. El publicador siempre recibe una confirmación normal; de lo contrario daría la entrega por fallida y lo reenviaría todo.

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 reglaSignificado
Filtroqué topics se reenvían
Sentidoout, in o both
QoScalidad de entrega a través del puente
Prefijosqué 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.

El puente habla QoS 0 y 1; el QoS 2 se rebaja a 1, y la entrega en QoS 1 se hace con el mejor esfuerzo.

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.

Esta API gestiona la lista de usuarios interna. Si hay seleccionada una fuente externa, las cuentas viven allí y deben crearse en la propia fuente.

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».
Cómo aguanta el broker bajo carga es objeto de un informe aparte: pruebas de carga (hasta 30 000 conexiones, latencia desde 73 µs, entrega de hasta 1,35 M de mensajes/s).