Documentação

Tudo o que é preciso para colocar o broker no ar e configurá-lo. A ajuda embutida do painel espelha estas seções e está traduzida para sete idiomas.

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.

O administrador do painel não é uma conta MQTT. Os dispositivos se conectam com contas separadas criadas na seção Usuários.

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.

A configuração do nginx precisa repassar os cabeçalhos 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.

As configurações ficam em 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çãoO que define
-configcaminho do config.json
-datadiretório de dados
-mqttendereço do MQTT sobre TCP
-mqtt-tlsendereço do MQTT sobre TLS
-webendereço do painel web
-lognível de log
-versionexibir a versão e sair
O 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:

CampoValores
Filtroum filtro MQTT comum: sensors/+/temp, dev/#, $u/#
Acessoread, write ou readwrite
Decisãopermitir 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.

FonteQuando serve
internalas contas são gerenciadas no painel — é o padrão
mysql / mariadbos dispositivos já vivem no banco de dados do seu sistema
sqliteo mesmo, mas o banco é um arquivo
csvuma lista simples; os arquivos são recarregados quando mudam
jwto dispositivo apresenta um token assinado em vez de uma senha
httpo 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.

O algoritmo de assinatura é tomado apenas da configuração, nunca do cabeçalho do token: uma falsificação com "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:

QuandoFiltroExpressãoNovo tópico
Sempreraw/#^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:

CampoO que define
Padrão de tópicoum filtro MQTT comum: sensors/+/temp
Açãoreduzir a uma taxa ou descartar por completo
Mensagens por segundoa taxa desejada; frações são permitidas (0.2 é uma a cada cinco segundos)
Contar porcliente e tópico, ou o tópico como um todo
A redução mantém o último valor: uma mensagem que chega cedo demais fica retida, a seguinte a substitui, e no próximo tique sai a mais recente. O publicador sempre recebe uma confirmação normal — caso contrário consideraria a entrega falha e reenviaria tudo.

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 regraSignificado
Filtroquais tópicos encaminhar
Direçãoout, in ou both
QoSqualidade de entrega através da ponte
Prefixoso 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.

A ponte fala QoS 0 e 1; o QoS 2 é rebaixado para 1, e a entrega em QoS 1 é feita com o melhor esforço.

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.

Esta API gerencia a lista de usuários interna. Se houver uma fonte externa selecionada, as contas vivem lá e precisam ser criadas na própria fonte.

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».
Como o broker se comporta sob carga é assunto de um relatório à parte: testes de carga (até 30 000 conexões, latência a partir de 73 µs, entrega de até 1,35 milhão de mensagens/s).