Schnellstart
Nach der Installation lauscht der Broker auf drei Ports: :1883 für MQTT über TCP, :8883 für MQTT über TLS und :8567 für das Web-Dashboard sowie MQTT über WebSocket unter dem Pfad /mqtt.
Öffnen Sie http://localhost:8567 und melden Sie sich als Administrator an. Die Standardanmeldung lautet admin / admin; ändern Sie das Passwort direkt nach der ersten Anmeldung im Abschnitt Profil.
Legen Sie Ihren ersten Benutzer an: einen Namen, ein Passwort mit mindestens acht Zeichen und eine ACL-Regel. Die Regel $u/# gibt einem Gerät vollen Zugriff auf seinen eigenen Zweig — im Dashboard gibt es dafür die Schaltfläche „Eigener Zweig“.
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 unter Linux
Der empfohlene Weg ist das APT-Repository: Aktualisierungen kommen mit den Systemupdates.
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
Das Paket installiert die Binärdatei nach /opt/elxmqttbroker, legt einen Systembenutzer elxmqtt ohne Anmeldemöglichkeit an, platziert die Daten und config.json (Modus 0600) daneben und aktiviert den Dienst elxmqttbroker beim Systemstart.
systemctl status elxmqttbroker # Status
sudo systemctl restart elxmqttbroker # Neustart
journalctl -u elxmqttbroker -f # Protokolle
Die Unit ist mit ProtectSystem=strict abgesichert: Nur das eigene Verzeichnis des Brokers ist beschreibbar. Standardmäßig lauscht das Dashboard auf 127.0.0.1:8567 und wird über nginx veröffentlicht, während die MQTT-Ports 1883 und 8883 direkt erreichbar sind — das ist ein eigenes Protokoll und braucht keinen Proxy.
Upgrade und Connection weiterreichen und ein großzügiges proxy_read_timeout setzen: /ws/live und /mqtt sind langlebige WebSocket-Verbindungen.Installation unter Windows
Der übliche Weg ist das Installationsprogramm elxmqttbroker-setup.exe: Es legt das Programm nach Program Files, die Daten nach C:\ProgramData\ELX MQTT Broker, registriert auf Wunsch den Dienst ELXMQTTBroker für den Systemstart und öffnet die Ports 1883, 8883 und 8567 in der Firewall. Es spricht Russisch und Englisch und benötigt Administratorrechte.
ProgramData und nicht neben dem Programm: Der Broker schreibt config.json aus dem Dashboard heraus selbst, und ein Dienst hat in Program Files nichts zu schreiben. Beim Deinstallieren bleibt dieser Ordner erhalten — er enthält die Benutzer, deren Rechte und die Nachrichten.Der portable Weg ist eine einzelne elxmqttbroker.exe: in einen eigenen Ordner legen und starten, woraufhin daneben config.json, ein Verzeichnis data und ein selbstsigniertes TLS-Zertifikat entstehen.
elxmqttbroker.exe # mit den Standardwerten starten
elxmqttbroker.exe -web :9000 # Dashboard auf einem anderen Port
elxmqttbroker.exe -version # Version und Build-Stempel
Eine portable Kopie lässt sich von Hand als Dienst betreiben, mit denselben Befehlen, die auch das Installationsprogramm verwendet:
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
Konfiguration
config.json ist die einzige Datei, die der Broker liest. Sie entsteht beim ersten Start und enthält nur, was vor dem Start bekannt sein muss: Adressen, TLS und das Administratorkonto.
{
"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
}
Ein password im Klartext wird beim ersten Start in einen passwordHash verwandelt und aus der Datei entfernt. Alles Übrige — Protokoll-Limits, SMTP, Bridges, Regeln, API-Tokens, MQTT-Benutzer — wird im Dashboard eingestellt und liegt in data/users.json; ein Neustart ist dafür nirgends nötig.
Kommandozeilenschalter haben Vorrang vor der Datei:
| Schalter | Was er setzt |
|---|---|
| -config | Pfad zu config.json |
| -data | Datenverzeichnis |
| -mqtt | Adresse für MQTT über TCP |
| -mqtt-tls | Adresse für MQTT über TLS |
| -web | Adresse des Web-Dashboards |
| -log | Protokollstufe |
| -version | Version ausgeben und beenden |
config.json enthält den Passwort-Hash des Administrators, das SMTP-Passwort und die Zugangsdaten der externen Authentifizierungsquelle. Die Datei sollte den Modus 0600 haben.Benutzer und Rechte
Es gibt zwei Kreise, und sie sollten nicht verwechselt werden. Der Administrator ist ein einzelnes, in config.json definiertes Konto, das ausschließlich das Dashboard verwaltet: keine Rollen, keine Registrierung, und wer drin ist, hat vollen Zugriff. MQTT-Geräte sind eine eigene Kontenliste: ein Name von 1 bis 64 Zeichen, ein Passwort, ein Aktiv-Schalter und Topic-Rechte.
Eine ACL-Regel besteht aus einem Topic-Filter, einer Zugriffsart und einer Entscheidung:
| Feld | Werte |
|---|---|
| Filter | ein gewöhnlicher MQTT-Filter: sensors/+/temp, dev/#, $u/# |
| Zugriff | read, write oder readwrite |
| Entscheidung | erlauben oder verbieten |
Regeln werden von oben nach unten geprüft, der erste Treffer gewinnt, und alles gilt als Deny-by-default: Ohne ausdrückliche Erlaubnis gibt es keinen Zugriff. Die Reihenfolge ist Teil der Konfiguration, deshalb lassen sich Regeln mit der Maus ziehen oder mit den Pfeiltasten verschieben.
Der Filter erweitert $u — den Namen des verbundenen Clients. Eine einzige Regel $u/# beschränkt jedes Gerät auf seinen eigenen Zweig und erspart Ihnen eine Regel je Name.
Passwörter werden als PBKDF2-HMAC-SHA256 mit 210 000 Iterationen und zufälligem Salt gespeichert. Sitzungs- und API-Tokens werden ausschließlich als Hash abgelegt.
MQTT-Authentifizierung
Die Quelle der Zugangsdaten wird unter Einstellungen → Authentifizierung gewählt, und es ist immer genau eine aktiv. Der Wechsel erfolgt im laufenden Betrieb: Die neue Quelle wird zuerst mit der Schaltfläche „Test“ geprüft, und nur wenn sie antwortet, schaltet der Broker um und trennt die Clients, damit sich jeder neu authentifiziert. Ist die Quelle nicht erreichbar, ändert sich nichts.
| Quelle | Wann sie passt |
|---|---|
internal | Konten werden im Dashboard verwaltet — die Voreinstellung |
mysql / mariadb | die Geräte stehen bereits in der Datenbank Ihres Systems |
sqlite | dasselbe, nur ist die Datenbank eine Datei |
csv | eine einfache Liste; Dateien werden bei Änderung neu geladen |
jwt | das Gerät weist statt eines Passworts ein signiertes Token vor |
http | Ihr Dienst entscheidet bei jeder Verbindung |
Das Schema für MySQL und MariaDB folgt 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} und ${clientid} werden als Abfrageparameter gebunden statt zusammengesetzt, sodass Injection unmöglich ist. passwordHash akzeptiert plain, sha256, sha512, bcrypt und pbkdf2.
Ein JWT kommt in das Passwort- oder Benutzernamenfeld. Unterstützt werden HS256/384/512 und RS256/384/512; geprüft werden Signatur, exp und nbf, wahlweise auch iss, aud und beliebige eigene Claims. Die Rechte stammen aus dem Claim acl in einem der beiden EMQX-Formate, und is_superuser hebt die Prüfung vollständig auf.
"alg": "none" kommt nicht durch.Die HTTP-Quelle erhält {username, password, clientid, peerhost} und antwortet mit {"result": "allow", "acl": […]}. Eine leere 200 gilt als Erlaubnis; deny, 401, 403, eine Zeitüberschreitung und jeder Fehler sind eine Ablehnung — ein nicht erreichbarer Autorisierungsdienst darf nicht zur offenen Tür werden. Antworten werden für cacheSeconds zwischengespeichert.
Regeln: Rewrite, Auto-Subscribe, Limits
Der Topic-Rewrite ersetzt einen Topic-Namen im laufenden Betrieb. Eine Regel besteht aus einem MQTT-Filter zur günstigen Vorauswahl, einem regulären Ausdruck und einer Zielvorlage mit den Gruppen $1…$9:
| Wann | Filter | Ausdruck | Neues Topic |
|---|---|---|---|
| Immer | raw/# | ^raw/(.+)$ | cooked/$1 |
Die Reihenfolge folgt EMQX: erst Rewrite, dann ACL-Prüfung — die Rechte werden gegen das Topic geprüft, unter dem die Nachricht tatsächlich läuft. UNSUBSCRIBE durchläuft denselben Rewrite wie SUBSCRIBE, sonst könnte ein Client sein Abonnement nie beenden.
Auto-Subscribe erzeugt Abonnements direkt nach dem Verbinden, ohne SUBSCRIBE vom Client. Eine Regel %c/# oder %u/# gibt jedem Client seinen eigenen Zweig, ganz ohne manuelle Einrichtung.
Topic-Limits sind für den Fall gedacht, dass ein Client insgesamt in Ordnung ist, aber ein bestimmtes Topic viel zu häufig eintrifft:
| Feld | Was es setzt |
|---|---|
| Topic-Muster | ein gewöhnlicher MQTT-Filter: sensors/+/temp |
| Aktion | auf eine Rate ausdünnen oder ganz verwerfen |
| Nachrichten pro Sekunde | die Zielrate; Bruchteile sind erlaubt (0.2 ist eine alle fünf Sekunden) |
| Zählen nach | Client und Topic oder das Topic als Ganzes |
Die Flood Control wird unter Einstellungen → Broker konfiguriert und gilt je Verbindung: Nachrichten pro Sekunde, Nachrichten-Burst, Bytes pro Sekunde, Byte-Burst. Null bedeutet kein Limit. Ein Überschreiten trennt die Verbindung nicht: Der Broker pausiert vor dem nächsten Lesen des Sockets, TCP schließt das Fenster, und der Sender wird von selbst langsamer.
Verzögertes Publish
Eine Veröffentlichung auf $delayed/{Sekunden}/{Topic} hält der Broker zurück und gibt sie an die Abonnenten weiter, wenn sie fällig wird. Das Format ist EMQX-kompatibel.
mosquitto_pub -t '$delayed/60/sensors/alarm' -m 'in einer Minute'
Das Intervall reicht von einer Sekunde bis 4 294 967 (etwa 49 Tage). Die Bestätigung kommt sofort: Der Broker bürgt für den Empfang, nicht für die Existenz von Abonnenten. Die Auflösung beträgt eine Sekunde.
Die Warteschlange ist unter Regeln → Verzögert sichtbar: Topic, Payload, Countdown sowie Abbrechen einzeln oder auf einmal. Nachrichten überstehen einen Neustart, und alles, was fällig wurde, während der Broker aus war, wird gleich nach dem Start ausgeliefert.
Broker-Bridging
Der Broker kann sich als Client mit einem anderen MQTT-Broker verbinden und Topics in beide Richtungen weiterleiten. Eingerichtet wird das unter Einstellungen → Bridges: die entfernte Adresse (der Port ist optional — 1883 als Standard, 8883 über TLS), Anmeldung, TLS, Protokollversion und Regeln.
| Regelfeld | Bedeutung |
|---|---|
| Filter | welche Topics weitergeleitet werden |
| Richtung | out, in oder both |
| QoS | Zustellgüte über die Bridge |
| Präfixe | was auf welcher Seite vorangestellt wird |
Es gibt Schleifenschutz, automatischen Reconnect, No Local bei Version 5 (kein Echo, keine Duplikate) sowie Status und Zähler im Dashboard. Die Bridge arbeitet auf Brokerebene und nicht als separater Client.
REST-API
Das Dashboard ruft seine eigene API mit einem Sitzungscookie auf; externe Systeme nutzen Bearer-Tokens aus Einstellungen → API. Ein Token wird einmal angezeigt, gespeichert wird nur sein Hash. Ein Token kann nur lesend ausgestellt werden — dann kommen ausschließlich GET, HEAD und OPTIONS durch.
curl -H "Authorization: Bearer TOKEN" http://localhost:8567/api/stats
Das typische Szenario ist, dass Ihr System ein Gerät anlegt und ihm zugleich den Zugang zum Broker gewährt:
# anlegen
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}]}'
# Passwort oder Rechte ändern (nur die gesendeten Felder)
curl -X PATCH http://localhost:8567/api/users/sensor-42 \
-H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" \
-d '{"password":"newPass12345","enabled":false}'
# löschen
curl -X DELETE http://localhost:8567/api/users/sensor-42 \
-H "Authorization: Bearer TOKEN"
Das Passwort wird nie zurückgegeben. Fehler kommen in einer einheitlichen Form, {"error":{"code":"…","message":"…"}}: duplicate, reserved, invalid_input, not_found, read_only, unauthorized.
Änderungen wirken sofort: Bei einer Passwortänderung, einer Rechteänderung oder einer Löschung trennt der Broker die laufenden Verbindungen dieses Benutzers selbst, damit die neuen Regeln unmittelbar greifen und nicht erst beim nächsten Verbinden.
Die gesamte Dashboard-API steht zur Verfügung: Statistiken und Verlauf, Clients, Abonnements, Retained Messages, Veröffentlichen, Ereignisse, Benutzer, Einstellungen, Bridges, Regeln, verzögerte Nachrichten, Import und Export.
Speicherung und Neustarts
Mit persistence: true liegt der Zustand in data/broker.db — SQLite im WAL-Modus, reines Go, ohne CGO. Was einen Neustart übersteht:
- Retained Messages — bei jeder Änderung sofort geschrieben, nicht nach Zeitplan. Alles, dessen Message Expiry abgelaufen ist, wird beim Start verworfen.
- Persistente Sitzungen — Abonnements, Offline-Warteschlangen für QoS 1/2 und unvollendete Handshakes. Alle zehn Sekunden und beim Herunterfahren gesichert. Clean Sessions werden nicht gespeichert: Laut Spezifikation enden sie mit der Verbindung.
- Verzögerte Nachrichten — alles, was fällig wurde, während der Broker aus war, wird gleich nach dem Start ausgeliefert.
Beim Start landet eine Zeile wie state restored retained=128 sessions=7 subscriptions=34 delayed=2 im Log. Daneben liegen in data/ die Datei users.json (Konten, Regeln und Dashboard-Einstellungen, atomar geschrieben) und das selbstsignierte Zertifikat.
Bekannte Einschränkungen
- Clustering wird nicht unterstützt: Der Broker ist als einzelner Prozess entworfen.
- Die Bridge spricht QoS 0 und 1; QoS 2 wird auf 1 herabgestuft.
- Erweiterte Authentifizierung wie SCRAM existiert im Protokoll, die interne Quelle bietet sie aber nicht an und antwortet mit
0x8C Bad authentication method. - Die Ratenbegrenzung gilt je Verbindung und nicht je Benutzer: Ein Client, der zehn Verbindungen öffnet, bekommt zehn Limits.
- Der Systemzustand wird unter Linux und Windows berechnet; unter macOS und BSD sagt die Karte ehrlich „keine Daten“.