Início rápido
Depois da instalação o broker escuta em três portas: :1883 para MQTT sobre TCP, :8883 para MQTT sobre TLS e :8567 para o painel web e MQTT sobre WebSocket no caminho /mqtt.
Abra http://localhost:8567 e entre como administrador. O acesso padrão é admin / admin; troque a senha na seção Perfil logo após o primeiro login.
Crie seu primeiro usuário: um nome, uma senha de pelo menos oito caracteres e uma regra de ACL. A regra $u/# dá ao dispositivo acesso completo ao próprio ramo — o painel tem um botão «Ramo próprio» justamente para isso.
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
Instalação no Linux
O caminho recomendado é o repositório APT: as atualizações chegam junto com as do 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
O pacote instala o binário em /opt/elxmqttbroker, cria um usuário de sistema elxmqtt sem login, coloca ao lado os dados e o config.json (modo 0600) e ativa o serviço elxmqttbroker na inicialização.
systemctl status elxmqttbroker # estado
sudo systemctl restart elxmqttbroker # reinício
journalctl -u elxmqttbroker -f # logs
A unidade é restringida por ProtectSystem=strict: só o diretório do próprio broker aceita escrita. Por padrão o painel escuta em 127.0.0.1:8567 e é publicado via nginx, enquanto as portas MQTT 1883 e 8883 ficam expostas diretamente — é outro protocolo e não precisa de proxy.
Upgrade e Connection e definir um proxy_read_timeout generoso: /ws/live e /mqtt são conexões WebSocket de longa duração.Instalação no Windows
O caminho usual é o instalador elxmqttbroker-setup.exe: ele coloca o programa em Program Files, os dados em C:\ProgramData\ELX MQTT Broker, registra opcionalmente o serviço ELXMQTTBroker para iniciar com o sistema e abre as portas 1883, 8883 e 8567 no firewall. Fala russo e inglês e exige direitos de administrador.
ProgramData e não ao lado do programa: o broker reescreve o config.json a partir do painel, e um serviço não deve escrever em Program Files. Ao desinstalar, essa pasta permanece — ela guarda os usuários, as permissões deles e as mensagens.O caminho portátil é um único elxmqttbroker.exe: coloque-o em uma pasta própria e execute, e ao lado surgirão config.json, um diretório data e um certificado TLS autoassinado.
elxmqttbroker.exe # executar com os valores padrão
elxmqttbroker.exe -web :9000 # painel em outra porta
elxmqttbroker.exe -version # versão e selo de compilação
Uma cópia portátil pode ser operada como serviço à mão, com os mesmos comandos que o instalador usa:
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
Configuração
O config.json é o único arquivo que o broker lê. Ele é criado na primeira execução e guarda só o que precisa ser conhecido antes de iniciar: endereços, TLS e a conta do 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
}
Uma password em texto puro vira passwordHash na primeira execução e é apagada do arquivo. Todo o resto — limites do protocolo, SMTP, pontes, regras, tokens de API, usuários MQTT — é configurado no painel e fica em data/users.json; nada disso exige reiniciar.
As opções de linha de comando têm precedência sobre o arquivo:
| Opção | O que define |
|---|---|
| -config | caminho do config.json |
| -data | diretório de dados |
| -mqtt | endereço do MQTT sobre TCP |
| -mqtt-tls | endereço do MQTT sobre TLS |
| -web | endereço do painel web |
| -log | nível de log |
| -version | exibir a versão e sair |
config.json contém o resumo da senha do administrador, a senha do SMTP e as credenciais da fonte de autenticação externa. O arquivo deve estar no modo 0600.Usuários e permissões
Há dois circuitos, e não convém confundi-los. O administrador é uma única conta definida no config.json que cuida apenas do painel: sem papéis, sem cadastro, e quem entra tem acesso completo. Os dispositivos MQTT formam uma lista de contas separada: um nome de 1 a 64 caracteres, uma senha, um indicador de ativação e permissões por tópico.
Uma regra de ACL é composta por um filtro de tópico, um modo de acesso e uma decisão:
| Campo | Valores |
|---|---|
| Filtro | um filtro MQTT comum: sensors/+/temp, dev/#, $u/# |
| Acesso | read, write ou readwrite |
| Decisão | permitir ou negar |
As regras são verificadas de cima para baixo, vence a primeira correspondência e tudo é negado por padrão: sem uma permissão explícita não há acesso. A ordem faz parte da configuração, então as regras podem ser arrastadas com o mouse ou movidas com as setas.
O filtro expande $u — o nome do cliente que se conecta. Uma única regra $u/# confina cada dispositivo ao próprio ramo e poupa uma regra por nome.
As senhas são guardadas como PBKDF2-HMAC-SHA256 com 210 000 iterações e sal aleatório. Tokens de sessão e de API ficam guardados apenas como resumo.
Autenticação MQTT
A fonte de credenciais é escolhida em Configurações → Autenticação, e apenas uma fica ativa por vez. A troca acontece em tempo real: a nova fonte é primeiro verificada com o botão Testar e só se ela responder o broker muda e desconecta os clientes para que cada um se autentique de novo. Se a fonte estiver inacessível, nada muda.
| Fonte | Quando serve |
|---|---|
internal | as contas são gerenciadas no painel — é o padrão |
mysql / mariadb | os dispositivos já vivem no banco de dados do seu sistema |
sqlite | o mesmo, mas o banco é um arquivo |
csv | uma lista simples; os arquivos são recarregados quando mudam |
jwt | o dispositivo apresenta um token assinado em vez de uma senha |
http | o seu serviço decide a cada conexão |
O esquema de MySQL e MariaDB segue o do 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} e ${clientid} são vinculados como parâmetros da consulta em vez de concatenados, então injeção é impossível. passwordHash aceita plain, sha256, sha512, bcrypt e pbkdf2.
Um JWT vai no campo de senha ou de usuário. Há suporte a HS256/384/512 e RS256/384/512; são verificados a assinatura, exp e nbf e, opcionalmente, iss, aud e quaisquer claims próprios. As permissões vêm do claim acl em qualquer um dos formatos do EMQX, e is_superuser dispensa a verificação por completo.
"alg": "none" não passa.A fonte HTTP recebe {username, password, clientid, peerhost} e responde com {"result": "allow", "acl": […]}. Um 200 vazio conta como permissão; deny, 401, 403, um tempo esgotado e qualquer erro são recusa — um serviço de autorização inacessível não pode virar porta aberta. As respostas ficam em cache por cacheSeconds.
Regras: reescrita, assinatura automática, limites
A reescrita de tópicos substitui o nome de um tópico em tempo real. Uma regra é um filtro MQTT para uma pré-seleção barata, uma expressão regular e um modelo de destino com os grupos $1…$9:
| Quando | Filtro | Expressão | Novo tópico |
|---|---|---|---|
| Sempre | raw/# | ^raw/(.+)$ | cooked/$1 |
A ordem segue o EMQX: primeiro a reescrita, depois a verificação de ACL — as permissões são conferidas sobre o tópico pelo qual a mensagem realmente vai trafegar. O UNSUBSCRIBE passa pela mesma reescrita do SUBSCRIBE, senão um cliente nunca conseguiria cancelar a assinatura.
A assinatura automática cria assinaturas logo após a conexão, sem SUBSCRIBE por parte do cliente. Uma regra %c/# ou %u/# dá a cada cliente o próprio ramo sem configuração manual.
Os limites por tópico servem quando um cliente se comporta bem no geral, mas um tópico específico chega com frequência demais:
| Campo | O que define |
|---|---|
| Padrão de tópico | um filtro MQTT comum: sensors/+/temp |
| Ação | reduzir a uma taxa ou descartar por completo |
| Mensagens por segundo | a taxa desejada; frações são permitidas (0.2 é uma a cada cinco segundos) |
| Contar por | cliente e tópico, ou o tópico como um todo |
O controle de enxurrada é configurado em Configurações → Broker e vale por conexão: mensagens por segundo, rajada de mensagens, bytes por segundo e rajada de bytes. Zero significa sem limite. Exceder não derruba a conexão: o broker faz uma pausa antes da próxima leitura do socket, o TCP fecha a janela e o emissor se contém sozinho.
Publicação adiada
Uma publicação em $delayed/{segundos}/{tópico} fica retida no broker e é liberada aos assinantes quando vence. O formato é compatível com o EMQX.
mosquitto_pub -t '$delayed/60/sensors/alarm' -m 'daqui a um minuto'
O intervalo vai de um segundo a 4 294 967 (cerca de 49 dias). A confirmação chega na hora: o broker responde pelo recebimento, não pela existência de assinantes. A resolução é de um segundo.
A fila aparece em Regras → Adiadas: tópico, payload, contagem regressiva e cancelamento uma a uma ou de todas de uma vez. As mensagens sobrevivem a uma reinicialização, e as que venceram enquanto o broker esteve fora saem logo depois da inicialização.
Ponte entre brokers
O broker pode se conectar como cliente a outro broker MQTT e encaminhar tópicos nos dois sentidos. Isso se configura em Configurações → Pontes: o endereço remoto (a porta é opcional — 1883 por padrão, 8883 com TLS), as credenciais, TLS, a versão do protocolo e as regras.
| Campo da regra | Significado |
|---|---|
| Filtro | quais tópicos encaminhar |
| Direção | out, in ou both |
| QoS | qualidade de entrega através da ponte |
| Prefixos | o que acrescentar em cada lado |
Há proteção contra laços, reconexão automática, No Local na versão 5 (sem eco nem duplicatas) e estado e contadores no painel. A ponte funciona no nível do broker e não como um cliente à parte.
API REST
O painel chama a própria API com um cookie de sessão; sistemas externos usam tokens bearer de Configurações → API. Um token é exibido uma única vez e apenas o resumo dele é guardado. Um token pode ser emitido somente de leitura — então passam apenas GET, HEAD e OPTIONS.
curl -H "Authorization: Bearer TOKEN" http://localhost:8567/api/stats
O cenário típico é o seu sistema cadastrar um dispositivo e conceder a ele acesso ao broker no mesmo passo:
# criar
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}]}'
# mudar a senha ou as permissões (apenas os 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}'
# excluir
curl -X DELETE http://localhost:8567/api/users/sensor-42 \
-H "Authorization: Bearer TOKEN"
A senha nunca é devolvida. Os erros voltam em um formato único, {"error":{"code":"…","message":"…"}}: duplicate, reserved, invalid_input, not_found, read_only, unauthorized.
As mudanças valem na hora: ao trocar uma senha, alterar permissões ou excluir, o próprio broker derruba as conexões ativas daquele usuário, para que as novas regras passem a valer de imediato e não na próxima reconexão.
Toda a API do painel está disponível: estatísticas e histórico, clientes, assinaturas, mensagens retidas, publicação, eventos, usuários, configurações, pontes, regras, mensagens adiadas, importação e exportação.
Armazenamento e reinicializações
Com persistence: true o estado fica em data/broker.db — SQLite em modo WAL, Go puro, sem CGO. O que sobrevive a uma reinicialização:
- As mensagens retidas — gravadas assim que mudam, não por temporizador. Tudo o que passou do Message Expiry é descartado na inicialização.
- As sessões persistentes — assinaturas, filas offline de QoS 1/2 e handshakes inacabados. Salvas a cada dez segundos e no desligamento. Sessões limpas não são gravadas: pela especificação, elas morrem com a conexão.
- As mensagens adiadas — as que venceram enquanto o broker esteve fora saem logo depois da inicialização.
Na inicialização vai para o log uma linha como state restored retained=128 sessions=7 subscriptions=34 delayed=2. Ao lado, em data/, ficam o users.json (contas, regras e configurações do painel, gravado de forma atômica) e o certificado autoassinado.
Limitações conhecidas
- Não há suporte a cluster: o broker foi projetado como um processo único.
- A ponte fala QoS 0 e 1; o QoS 2 é rebaixado para 1.
- A autenticação reforçada do tipo SCRAM existe no protocolo, mas a fonte interna não a oferece e responde
0x8C Bad authentication method. - A limitação de taxa vale por conexão, e não por usuário: um cliente que abre dez conexões ganha dez limites.
- A saúde da máquina é calculada no Linux e no Windows; no macOS e no BSD a ficha diz honestamente «sem dados».