MQTT Gateway

bext acts as an MQTT 5 gateway broker — IoT devices connect via standard MQTT, and messages route into bext's plugin system and pub/sub infrastructure. bext is not a full-persistence broker; it bridges MQTT traffic into your application logic.

Enabling MQTT

Add a [mqtt] section to bext.config.toml:

[mqtt]
enabled = true
bind = "0.0.0.0:1883"
tls_bind = "0.0.0.0:8883"
max_connections = 10000
max_packet_size_bytes = 65536

Compile with the mqtt feature flag:

bext build --features mqtt

Listener Ports

MQTT runs on its own TCP listeners, separate from the HTTP port:

Port Protocol Description
1883 MQTT Plain TCP (LAN / dev use).
8883 MQTTS TLS-encrypted (production).

TLS uses the same certificate configured in the site's [tls] section.

Gateway Model

bext is a gateway, not a standalone broker. This means:

  • Incoming MQTT publishes are forwarded to bext plugins and the internal pub/sub bus.
  • Plugins can subscribe to MQTT topics and react to messages.
  • There is no built-in disk-backed message persistence. Messages that cannot be delivered are dropped after QoS retries.
  IoT Device ──mqtt──▶ bext ──▶ Plugin handler
                         │
                         └──▶ PubSub bus (SSE, WebSocket subscribers)

MQTT 5 Features

bext implements the MQTT 5.0 protocol (RFC 9431):

Quality of Service

QoS Level Guarantee Use Case
0 At most once (fire and forget) Sensor telemetry.
1 At least once (ack required) Commands, alerts.
2 Exactly once (4-step handshake) Billing, state changes.

Sessions

  • Clean Start — client starts fresh, no stored state.
  • Persistent Session — bext stores subscriptions and pending QoS 1/2 messages for the session expiry interval.
[mqtt]
session_expiry_secs = 3600   # 1 hour default

Topic Wildcards

Standard MQTT wildcard subscriptions are supported:

Wildcard Example Matches
+ sensors/+/temp sensors/room1/temp, etc.
# sensors/# Everything under sensors/.

Authentication

MQTT clients authenticate via the token-in-username pattern. The client sends a bearer token as the MQTT username, and bext validates it through the same Auth capability used for HTTP:

Username: Bearer eyJhbGciOi...
Password: (empty or ignored)

Alternatively, use client certificate authentication over MQTTS for device fleets where token management is impractical.

[mqtt.auth]
mode = "token"        # "token" | "cert" | "none"

HTTP Publish Bridge

Publish MQTT messages from any HTTP client via the built-in bridge endpoint:

POST /__bext/mqtt/publish
Content-Type: application/json

{
  "topic": "sensors/room1/temp",
  "payload": "22.5",
  "qos": 1,
  "retain": false
}

This is useful for backend services that do not have an MQTT client library, or for triggering device commands from a web dashboard.

Plugin Integration

Plugins can subscribe to MQTT topics and publish messages:

use bext::mqtt::{MqttBus, MqttMessage};

async fn on_mqtt_message(msg: MqttMessage, bus: &MqttBus) {
    println!("topic={} payload={}", msg.topic, msg.payload_str());

    // Publish a response
    bus.publish("devices/ack", b"ok", QoS::AtLeastOnce).await?;
}

Register the subscription in the plugin manifest:

[plugin]
name = "sensor-handler"

[[plugin.mqtt_subscriptions]]
topic = "sensors/+/temp"
qos = 1

Retained Messages

When retain = true, bext stores the last message per topic in memory. New subscribers immediately receive the retained message for matching topics. This is standard MQTT behavior for "last known value" patterns.

Will Messages

Clients can set a Last Will and Testament (LWT) on connect. If the client disconnects ungracefully, bext publishes the will message to the specified topic:

Will Topic: devices/sensor-42/status
Will Payload: offline
Will QoS: 1
Will Retain: true

Metrics

Metric Description
mqtt_connections_active Current MQTT client connections.
mqtt_messages_received_total Messages received from clients.
mqtt_messages_sent_total Messages sent to clients.
mqtt_subscriptions_active Active topic subscriptions.

Feature Flag

MQTT requires the mqtt feature flag:

bext build --features mqtt

Without this flag, the [mqtt] config section is ignored.

Warning

bext is a gateway, not a persistence broker. Messages that cannot be delivered within QoS retry limits are dropped — there is no durable queue behind them. For workloads that require guaranteed delivery across broker restarts, bridge to an external broker (Mosquitto, EMQX, etc.) from a plugin rather than relying on bext's in-memory session store.

Tip

Port 1883 (plain TCP) is suitable for LAN or dev use only. In production, use port 8883 (MQTTS) and the cert auth mode so device credentials are not transmitted in plaintext.

Related

Links