A lightweight MQTT man-in-the-middle proxy that terminates TLS from a client device, forwards traffic to the original destination broker over TLS, and mirrors a copy of the traffic to a second (local) MQTT broker.
Designed for IoT monitoring scenarios where you need visibility into MQTT traffic between a device and a cloud broker (e.g. Azure IoT Hub) without modifying the device firmware.
- TLS termination — presents a server certificate to the client, connects upstream over TLS
- Transparent forwarding — all MQTT packets are forwarded to the destination broker unmodified
- Traffic mirroring — copies PUBLISH, SUBSCRIBE, and UNSUBSCRIBE packets to a secondary MQTT broker
- Topic prefixing — optionally prepends a configurable prefix to all mirrored topics (e.g.
devices/foo→aqualisa/devices/foo) - Auto-generated certificates — generates a CA and server certificate on first run if not provided
- DNS resolution via Google — resolves the destination host using
8.8.8.8to bypass local DNS overrides (useful when the proxy itself intercepts the destination hostname) - Persistent mirror connection — maintains a single connection to the mirror broker with automatic reconnection
docker run -d \
--name mqtt_proxy \
-p 8883:8883 \
-v /path/to/config:/data \
hmchan/mqtt_proxy:latestMount a directory containing mqtt_proxy.ini to /data:
[proxy]
listen_port = 8883
dest_host = your-iot-hub.azure-devices.net
dest_port = 8883
debug = false
# Certificate paths (auto-generated if not present)
ca_cert = /data/ca.crt
server_cert = /data/server.crt
server_key = /data/server.key
[mirror]
host = mqtt
port = 1883
username = user
password = password
topic_prefix = myprefix/| Setting | Description |
|---|---|
listen_port |
Port to listen on for incoming MQTT TLS connections |
dest_host |
Destination MQTT broker hostname |
dest_port |
Destination MQTT broker port |
debug |
Enable verbose hex dump logging (true/false) |
ca_cert |
Path to CA certificate (generated if missing) |
server_cert |
Path to server certificate (generated if missing) |
server_key |
Path to server private key (generated if missing) |
| Setting | Description |
|---|---|
host |
Mirror MQTT broker hostname |
port |
Mirror MQTT broker port |
username |
Mirror broker username |
password |
Mirror broker password |
topic_prefix |
Optional prefix added to all mirrored topics (leave empty to disable) |
services:
mqtt:
image: eclipse-mosquitto:2.0
ports:
- "1883:1883"
mqtt_proxy:
image: hmchan/mqtt_proxy:latest
restart: unless-stopped
volumes:
- /path/to/config:/data
ports:
- "8883:8883"On first run, if ca.crt, server.crt, and server.key are not found in /data, the proxy auto-generates:
- A self-signed CA certificate
- A server certificate signed by the CA, matching the
dest_hosthostname
Install the generated ca.crt on your client device to trust the proxy.
You can also provide your own certificates by placing them in the mounted /data directory before starting the container.
IoT Device ──TLS──▶ Proxy (:8883) ──TLS──▶ Cloud Broker (dest_host:dest_port)
│
└──plain──▶ Mirror Broker (host:port)
(with optional topic prefix)
- The device connects to the proxy over TLS
- The proxy connects to the real broker over TLS and forwards all traffic transparently
- PUBLISH, SUBSCRIBE, and UNSUBSCRIBE packets are copied to the mirror broker
- CONNECT packets are skipped (the mirror uses its own authentication)
- Control packets (PINGREQ, PUBACK, etc.) are forwarded to the mirror as-is