Démarrage rapide
Après l'installation, le broker écoute sur trois ports : :1883 pour MQTT sur TCP, :8883 pour MQTT sur TLS, et :8567 pour le tableau de bord web ainsi que MQTT sur WebSocket au chemin /mqtt.
Ouvrez http://localhost:8567 et connectez-vous en administrateur. L'identifiant par défaut est admin / admin ; changez le mot de passe dans la section Profil juste après la première connexion.
Créez votre premier utilisateur : un nom, un mot de passe d'au moins huit caractères et une règle ACL. La règle $u/# donne à un appareil un accès complet à sa propre branche — le tableau de bord propose un bouton « Branche propre » exactement pour cela.
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
Installation sous Linux
La voie recommandée est le dépôt APT : les mises à jour arrivent avec celles du système.
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
Le paquet installe le binaire dans /opt/elxmqttbroker, crée un utilisateur système elxmqtt sans connexion possible, place les données et config.json (mode 0600) à côté, et active le service elxmqttbroker au démarrage.
systemctl status elxmqttbroker # état
sudo systemctl restart elxmqttbroker # redémarrage
journalctl -u elxmqttbroker -f # journaux
L'unité est verrouillée par ProtectSystem=strict : seul le répertoire du broker est accessible en écriture. Par défaut, le tableau de bord écoute sur 127.0.0.1:8567 et se publie par nginx, tandis que les ports MQTT 1883 et 8883 sont exposés directement — c'est un protocole distinct, qui n'a pas besoin de mandataire.
Upgrade et Connection et prévoir un proxy_read_timeout généreux : /ws/live et /mqtt sont des connexions WebSocket de longue durée.Installation sous Windows
La voie habituelle est l'installateur elxmqttbroker-setup.exe : il met le programme dans Program Files, les données dans C:\ProgramData\ELX MQTT Broker, enregistre au besoin le service ELXMQTTBroker pour démarrer avec le système, et ouvre les ports 1883, 8883 et 8567 dans le pare-feu. Il parle russe et anglais et demande les droits d'administrateur.
ProgramData plutôt qu'à côté du programme : le broker réécrit config.json lui-même depuis le tableau de bord, et un service n'a pas à écrire dans Program Files. La désinstallation laisse ce dossier — il contient les utilisateurs, leurs droits et les messages.La voie portable est un unique elxmqttbroker.exe : placez-le dans son propre dossier et lancez-le, et config.json, un répertoire data et un certificat TLS auto-signé apparaissent à côté.
elxmqttbroker.exe # lancer avec les valeurs par défaut
elxmqttbroker.exe -web :9000 # tableau de bord sur un autre port
elxmqttbroker.exe -version # version et empreinte de compilation
Une copie portable peut être pilotée comme un service à la main, avec les mêmes commandes que celles de l'installateur :
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
Configuration
config.json est le seul fichier que lit le broker. Il est créé au premier démarrage et ne contient que ce qui doit être connu avant le lancement : adresses, TLS et le compte administrateur.
{
"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
}
Un password en clair est transformé en passwordHash au premier démarrage puis effacé du fichier. Tout le reste — limites du protocole, SMTP, ponts, règles, jetons d'API, utilisateurs MQTT — se règle dans le tableau de bord et vit dans data/users.json ; aucun redémarrage n'est nécessaire pour cela.
Les options de ligne de commande priment sur le fichier :
| Option | Ce qu'elle règle |
|---|---|
| -config | chemin de config.json |
| -data | répertoire de données |
| -mqtt | adresse MQTT sur TCP |
| -mqtt-tls | adresse MQTT sur TLS |
| -web | adresse du tableau de bord web |
| -log | niveau de journalisation |
| -version | afficher la version et quitter |
config.json contient l'empreinte du mot de passe administrateur, le mot de passe SMTP et les identifiants de la source d'authentification externe. Le fichier devrait être en mode 0600.Utilisateurs et droits
Il y a deux circuits, à ne pas confondre. L'administrateur est un compte unique défini dans config.json qui ne gère que le tableau de bord : pas de rôles, pas d'inscription, et une fois entré on a tous les accès. Les appareils MQTT forment une liste de comptes distincte : un nom de 1 à 64 caractères, un mot de passe, un indicateur d'activation et des droits par topic.
Une règle ACL se compose d'un filtre de topic, d'un mode d'accès et d'une décision :
| Champ | Valeurs |
|---|---|
| Filtre | un filtre MQTT ordinaire : sensors/+/temp, dev/#, $u/# |
| Accès | read, write ou readwrite |
| Décision | autoriser ou refuser |
Les règles sont examinées de haut en bas, la première correspondance l'emporte, et tout est interdit par défaut : sans autorisation explicite, pas d'accès. L'ordre fait partie de la configuration, les règles se déplacent donc à la souris ou avec les touches fléchées.
Le filtre développe $u — le nom du client qui se connecte. Une seule règle $u/# confine chaque appareil à sa propre branche et vous épargne une règle par nom.
Les mots de passe sont stockés en PBKDF2-HMAC-SHA256 avec 210 000 itérations et un sel aléatoire. Les jetons de session et d'API ne sont conservés que sous forme d'empreinte.
Authentification MQTT
La source d'identifiants se choisit sous Réglages → Authentification, et une seule est active à la fois. Le changement se fait à chaud : la nouvelle source est d'abord vérifiée avec le bouton Test, et ce n'est que si elle répond que le broker bascule et déconnecte les clients pour que chacun se réauthentifie. Si la source est injoignable, rien ne change.
| Source | Quand elle convient |
|---|---|
internal | les comptes sont gérés dans le tableau de bord — le choix par défaut |
mysql / mariadb | les appareils vivent déjà dans la base de votre système |
sqlite | la même chose, mais la base est un fichier |
csv | une liste simple ; les fichiers sont rechargés quand ils changent |
jwt | l'appareil présente un jeton signé au lieu d'un mot de passe |
http | votre service décide à chaque connexion |
Le schéma MySQL et MariaDB suit celui d'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} et ${clientid} sont liés comme paramètres de requête plutôt que concaténés, l'injection est donc impossible. passwordHash accepte plain, sha256, sha512, bcrypt et pbkdf2.
Un JWT se place dans le champ mot de passe ou nom d'utilisateur. HS256/384/512 et RS256/384/512 sont pris en charge ; la signature, exp et nbf sont vérifiés, et facultativement iss, aud et vos propres revendications. Les droits viennent de la revendication acl dans l'un ou l'autre format EMQX, et is_superuser lève entièrement la vérification.
"alg": "none" ne passe pas.La source HTTP reçoit {username, password, clientid, peerhost} et répond par {"result": "allow", "acl": […]}. Une 200 vide vaut autorisation ; deny, 401, 403, un dépassement de délai et toute erreur valent refus — un service d'autorisation injoignable ne doit pas devenir une porte ouverte. Les réponses sont mises en cache pendant cacheSeconds.
Règles : réécriture, abonnement automatique, limites
La réécriture de topics remplace un nom de topic à la volée. Une règle se compose d'un filtre MQTT pour une présélection peu coûteuse, d'une expression régulière et d'un modèle de destination avec les groupes $1…$9 :
| Quand | Filtre | Expression | Nouveau topic |
|---|---|---|---|
| Toujours | raw/# | ^raw/(.+)$ | cooked/$1 |
L'ordre suit EMQX : réécriture d'abord, vérification ACL ensuite — les droits sont vérifiés sur le topic sous lequel le message circulera vraiment. UNSUBSCRIBE passe par la même réécriture que SUBSCRIBE, sinon un client ne pourrait jamais se désabonner.
L'abonnement automatique crée des abonnements dès la connexion, sans SUBSCRIBE du client. Une règle %c/# ou %u/# donne à chaque client sa propre branche sans réglage manuel.
Les limites par topic servent quand un client se comporte bien dans l'ensemble mais qu'un topic précis arrive beaucoup trop souvent :
| Champ | Ce qu'il règle |
|---|---|
| Motif de topic | un filtre MQTT ordinaire : sensors/+/temp |
| Action | réduire à une cadence ou écarter entièrement |
| Messages par seconde | la cadence visée ; les fractions sont permises (0.2 vaut un toutes les cinq secondes) |
| Compter par | client et topic, ou le topic dans son ensemble |
L'anti-inondation se configure sous Réglages → Broker et s'applique par connexion : messages par seconde, rafale de messages, octets par seconde, rafale d'octets. Zéro signifie aucune limite. Un dépassement ne coupe pas la connexion : le broker marque une pause avant la lecture suivante du socket, TCP referme la fenêtre, et l'émetteur ralentit de lui-même.
Publication différée
Une publication sur $delayed/{secondes}/{topic} est retenue par le broker et remise aux abonnés à l'échéance. Le format est compatible EMQX.
mosquitto_pub -t '$delayed/60/sensors/alarm' -m 'dans une minute'
L'intervalle va d'une seconde à 4 294 967 (environ 49 jours). L'accusé arrive immédiatement : le broker se porte garant de la réception, pas de l'existence d'abonnés. La résolution est d'une seconde.
La file est visible sous Règles → Différés : topic, charge utile, compte à rebours, et annulation un par un ou en bloc. Les messages survivent à un redémarrage, et tous ceux arrivés à échéance pendant l'arrêt du broker partent juste après le démarrage.
Pontage entre brokers
Le broker peut se connecter comme client à un autre broker MQTT et transférer des topics dans les deux sens. Cela se configure sous Réglages → Ponts : l'adresse distante (le port est facultatif — 1883 par défaut, 8883 en TLS), les identifiants, TLS, la version du protocole et les règles.
| Champ de règle | Signification |
|---|---|
| Filtre | quels topics transférer |
| Direction | out, in ou both |
| QoS | qualité de livraison sur le pont |
| Préfixes | ce qu'on ajoute de chaque côté |
Il y a une protection contre les boucles, une reconnexion automatique, No Local en version 5 (ni écho ni doublons), ainsi que l'état et des compteurs dans le tableau de bord. Le pont travaille au niveau du broker et non comme un client séparé.
API REST
Le tableau de bord appelle sa propre API avec un cookie de session ; les systèmes externes utilisent des jetons bearer depuis Réglages → API. Un jeton est affiché une seule fois et seule son empreinte est conservée. Un jeton peut être émis en lecture seule — alors seuls GET, HEAD et OPTIONS passent.
curl -H "Authorization: Bearer TOKEN" http://localhost:8567/api/stats
Le scénario typique est celui de votre système qui crée un appareil et lui accorde l'accès au broker dans la foulée :
# créer
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}]}'
# changer le mot de passe ou les droits (seuls les champs envoyés)
curl -X PATCH http://localhost:8567/api/users/sensor-42 \
-H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" \
-d '{"password":"newPass12345","enabled":false}'
# supprimer
curl -X DELETE http://localhost:8567/api/users/sensor-42 \
-H "Authorization: Bearer TOKEN"
Le mot de passe n'est jamais renvoyé. Les erreurs reviennent sous une forme unique, {"error":{"code":"…","message":"…"}} : duplicate, reserved, invalid_input, not_found, read_only, unauthorized.
Les changements s'appliquent immédiatement : lors d'un changement de mot de passe, de droits ou d'une suppression, le broker coupe lui-même les connexions actives de cet utilisateur, pour que les nouvelles règles prennent effet aussitôt et non à la reconnexion suivante.
Toute l'API du tableau de bord est disponible : statistiques et historique, clients, abonnements, messages retenus, publication, événements, utilisateurs, réglages, ponts, règles, messages différés, import et export.
Stockage et redémarrages
Avec persistence: true, l'état vit dans data/broker.db — SQLite en mode WAL, Go pur, sans CGO. Ce qui survit à un redémarrage :
- Les messages retenus — écrits immédiatement à chaque changement, pas à intervalle. Tout ce dont le Message Expiry est dépassé est écarté au démarrage.
- Les sessions persistantes — abonnements, files hors ligne QoS 1/2 et poignées de main inachevées. Sauvegardées toutes les dix secondes et à l'arrêt. Les sessions propres ne sont pas enregistrées : par spécification, elles meurent avec la connexion.
- Les messages différés — tous ceux arrivés à échéance pendant l'arrêt du broker partent juste après le démarrage.
Au démarrage, une ligne du type state restored retained=128 sessions=7 subscriptions=34 delayed=2 part dans le journal. À côté, dans data/, se trouvent users.json (comptes, règles et réglages du tableau de bord, écrit de façon atomique) et le certificat auto-signé.
Limitations connues
- Le clustering n'est pas pris en charge : le broker est conçu comme un processus unique.
- Le pont parle QoS 0 et 1 ; le QoS 2 est ramené à 1.
- L'authentification renforcée de type SCRAM existe dans le protocole, mais la source interne ne la propose pas et répond
0x8C Bad authentication method. - La limitation de cadence s'applique par connexion et non par utilisateur : un client qui ouvre dix connexions obtient dix limites.
- La santé de la machine est calculée sous Linux et Windows ; sous macOS et BSD, la fiche indique honnêtement « pas de données ».