Skip to main content
Skip table of contents

Connect Shelly to RabbitMQ over MQTT mTLS

Summary

This solution securely connects a Shelly IP device to RabbitMQ via the MQTT plugin using mutual TLS (mTLS), no passwords, using certificate based mutual authentication. A single Bash script installs and configures RabbitMQ, generates a private CA, server and client certificates, and then presents a table of configuration values. After it finishes, the only manual step on the Shelly is to upload ca.crt, client.crt, and client.key, copy those values into the MQTT settings, and save it. Supports RabbitMQ series selection (--rmq-series 3.13|4.0|4.1, default 4.1) from Team RabbitMQ’s Ubuntu noble repos and forces TLS 1.2 only. On 4.x, the MQTT client_id is enforced from the certificate SAN (URI) while the authenticated username still comes from the certificate CN; on 3.13, SAN->client_id binding isn’t available. You can control the connect host (and the server cert CN/SAN) via --connect-dns / --connect-ip. The script exports device certs to /etc/mqtt-cert and, by default, also issues a monitor cert (<client_id>-mon) in /etc/mqtt-cert-monitor with tarballs in /tmp/.

Result: encrypted, certificate-authenticated MQTT with least-privilege topic access.

Link to the script here.

Important: This script is for development/testing only, an example of what’s possible. Use with care and do not deploy as is to production.

Architecture

SCHEME
[Shelly device]
    |
    |  MQTT over TLS (mTLS) - port 8883
    v
[RabbitMQ MQTT listener]  --->  [amq.topic exchange]  --->  [queues/subscriptions]
           |                               |
           |                               ‘-- topic ACLs scoped to your MQTT prefix
           |
           ‘-- Management UI (HTTPS, 15671)
  • Transport: Shelly talks to RabbitMQ on 8883 (MQTTS). TLS is required; clients must present a valid certificate (mTLS), it forces TLS 1.2 only.

  • Identity: The device’s certificate CN maps to a RabbitMQ user (no username/password in Shelly).

  • Client ID binding: Enforced from certificate SAN (URI) on RabbitMQ 4.x . Username still comes from CN; 3.13 doesn’t support SAN→client_id)

  • Authorization: Topic ACLs restricted to your chosen MQTT prefix (plus read only shellies/command for compatibility)

  • Tenancy: MQTT doesn’t carry vhosts, so connections are routed to a dedicated vhost (e.g., /shelly) via mqtt.vhost.

  • Management: HTTPS UI on 15671

  • Plain ports: Disabled by default. You can temporarily keep 1883/15672 with --keep-plaintext during migration.

Quick reference

Concern

Decision

Port (data)

8883 / TCP (MQTTS with mTLS)

Port (admin)

15671 / TCP (HTTPS Management UI)

Identity

Cert CN -> RabbitMQ user

Client ID

User provided in Shelly; enforced via cert SAN

Vhost

/shelly (set via mqtt.vhost)

Topics

Restricted to your MQTT prefix (both slash and dot forms)

Secrets on device

Client key only (no passwords)

Plaintext

Off by default; opt-in with --keep-plaintext

TLS Version

TLS 1.2 only

Prerequisites

  • Tested environment (time of writing): Ubuntu 24.04 LTS (amd64), RabbitMQ 4.1 (installed via this script), Shelly firmware 1.7.1.

  • Install: from Team RabbitMQ repos pinned to Ubuntu noble.

  • Access: Shell on the host with sudo privileges; outbound internet for apt repos.

  • Addressing: Stable broker IP/DNS (script can auto-detect, fixed is better).

  • Time sync: NTP enabled (cert validity depends on correct time).

  • Optional: mosquitto-clients for quick end-to-end testing.

What the script does

  1. Install RabbitMQ 4.1 + Erlang on Ubuntu 24.04

    Uses Team RabbitMQ apt repos (the current recommended path) to get modern Erlang/RabbitMQ. https://www.rabbitmq.com/docs/install-debian

  2. Configure via rabbitmq.conf (not rabbitmq-env.conf)

    Runtime settings (listeners, TLS, plugins) live in rabbitmq.conf; rabbitmq-env.conf is only for environment variables. https://www.rabbitmq.com/docs/configure

  3. Enable MQTT + Management plugins

    Turns on native MQTT support and the HTTPS management/UI and enables rabbitmq_auth_mechanism_sslhttps://www.rabbitmq.com/docs/mqtt

    1. Enable detailed_queues_endpoint feature flag(UI only detail for Queues).

  4. Enforce mutual TLS (mTLS) for MQTT

    Sets ssl_options.verify = verify_peer and ssl_options.fail_if_no_peer_cert = true so clients must present a valid cert; forces TLS 1.2 only. https://www.rabbitmq.com/docs/mqtt#tls

  5. Passwordless cert login (CN → user)

    Enables mqtt.ssl_cert_login = true and ssl_cert_login_from = common_name. The mapped user must exist in RabbitMQ (no password needed). https://www.rabbitmq.com/docs/mqtt#tls-certificate-authentication

  6. Bind MQTT client_id to the certificate SAN (URI)

    On RabbitMQ 4.1, sets

BASH
mqtt.ssl_cert_client_id_from = subject_alternative_name

so the CONNECT client_id must match the cert SAN (prevents ID spoofing). https://www.rabbitmq.com/docs/mqtt#usage-of-client_id-extraction-from-client-certificates-for-authentication

This binds client_id to the cert SAN (URI). Username still comes from CN; if you want username from SAN instead, you’d switch to ssl_cert_login_from=subject_alternative_name and ssl_cert_login_san_type=uri in the config.

  1. Issue two client certs (same CN, different SANs)

    • device: SAN=URI:<client_id>

    • monitor: SAN=URI:<client_id>-mon

Lets you subscribe with the monitor cert without disconnecting the device (distinct client IDs).

  1. Lock down listeners & ports

  2. Create tenancy & permissions

  3. Output you use on the Shelly

    Writes an export folder with ca.crt, client.crt, client.key and prints a table of the exact values to copy into the Shelly MQTT settings.

Implementation

  1. Run the script

CODE
./shelly-rmq-mqtt/setup-mqtt-mtls.sh \
--admin-user admin \
--admin-pass 'Sh3lly-i0T!' \
-C 'Shelly-Group' \
--client-id 'test-device' \
--vhost /shelly \
--mqtt-prefix 1pm-mini

Helpful flags (as needed): --admin-user/--admin-pass, --ip <broker_ip>, --keep-plaintext, --no-monitor-cert, --debug.

CODE
--connect-dns <name> (CN/SAN for the server cert and what clients dial)
--connect-ip <ip> (adds IP to server cert SAN)
--rmq-series 3.13|4.0|4.1 (default 4.1)
--force-regen (rotate CA/server/client certs even if present)
--monitor-client-id <id> (defaults to <client_id>-mon)
--tls-dir <dir>  --export-dir <dir>  --monitor-export-dir <dir>
--log-level debug|info|warn|error
--admin-user/--admin-pass, --ip <broker_ip> (alias: --server-ip), --keep-plaintext, --no-monitor-cert, --debug

The script will run and will go over each step and will show a success indicator and an error.

Install Steps

When it finishes, note the summary table at the bottom:

  • Broker IP/ports

  • Client ID and MQTT prefix

  • Paths to ca.crt, client.crt, client.key (export folder)

  • Shelly config options

  • Management URL: https://<broker_ip>:15671

  • Admin user and password (password is auto-generated unless you pass --admin-pass)

  • Log file path: /tmp/rabbitmq-mqtt-setup.log

Summary Table
  1. Upload certificates to the Shelly

    1. Open Shelly Web UI → Settings → TLS Configuration.

    2. Upload the three files from the script’s export folder:

      • CA certificate: ca.crt

      • Client certificate: client.crt

      • Client private key: client.key

    3. Upload each file individually: select the file, click Upload, and wait for the popup confirming success. Repeat for all three.

MQTT Config
  1. Configure Shelly MQTT

    1. Open Shelly Web UI → Settings → MQTT.

    2. Configure the values from the script:

      1. Enable: Selected

      2. User TLS: Selected

      3. Use Client Certificate: Enabled

      4. RPC Status update: Enabled

      5. Generic Status Update: Enabled

      6. Server: Value from the script

      7. Client ID: Value from the script

      8. MQTT Prefix: Value from the script

    3. Click Save Settings and reboot the device

Once finished with the configuration, the device should look like this:

Shelly MQTT Config Web UI
  1. After the Shelly reboots, run the monitoring command printed by the script’s summary. It’s auto-generated from the values you provided and uses the monitor certificate (distinct client_id) so it won’t disconnect the device. You should see messages flowing from the Shelly to RabbitMQ.

monitoring test

You should see the Shelly connect and publish.

Pub data Shelly

You can also confirm success in the Shelly’s web interface: the MQTT icon in the top-right shows two arrows when connected. If you see the arrows, the device is actively linked to RabbitMQ over MQTT/TLS.

MQTT success connection indicator

Troubleshooting

  1. Time sync - Make sure broker & Shelly clocks are correct (NTP). Skewed time breaks TLS.

  2. Three files uploaded - ca.crt, client.crt, client.key (each uploaded individually, success popup).

  3. Client ID vs SAN - On RabbitMQ 4.1, the MQTT Client ID must match the cert SAN (URI). If they differ, connection is rejected.

    • On RabbitMQ 3.13, binding client_id from SAN is not supported; only CN->username is used.

  4. CN user exists - The cert CN must match an existing RabbitMQ user (no password needed with mTLS).

  5. Ports - Use 8883 (MQTTS). 1883/15672 are off unless you ran with --keep-plaintext.

  6. Firewall - If UFW is active, the script opens 8883 and 15671; otherwise it does not change firewall rules.

  7. Prefix - Topics must sit under your MQTT prefix or RabbitMQ ACLs will block them.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.