TLS & SSL Setup
By default, MQTT traffic is unencrypted. Enabling TLS encrypts all data in transit between your clients and the broker, preventing eavesdropping and man-in-the-middle attacks. This guide covers generating certificates and configuring Mosquitto for TLS inside BunkerM.
Why TLS Matters for MQTT
Without TLS, MQTT credentials (username and password) and message payloads are transmitted in plain text. Anyone with network access between a client and the broker can read or modify the traffic. TLS is essential for:
- Production deployments on the internet or shared networks
- IoT devices sending sensitive data (health metrics, security systems, industrial telemetry)
- Compliance with security requirements
Step 1: Generate a Self-Signed Certificate
For internal networks and testing, a self-signed CA is sufficient. Run these commands on your host machine:
# Create a directory for your certs
mkdir -p ~/bunkerm-certs && cd ~/bunkerm-certs
# Generate a CA key and certificate
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
-subj "/CN=BunkerM-CA"
# Generate a server key and certificate signing request
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
-subj "/CN=your-broker-hostname"
# Sign the server certificate with your CA
openssl x509 -req -days 3650 -in server.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt Replace your-broker-hostname with the hostname or IP your MQTT clients use to connect.
Step 2: Mount Certificates into the Container
Place your certificates where Mosquitto can read them by adding bind mounts to your Docker run command or Compose file:
docker run -d \
-p 1900:1900 \
-p 8883:8883 \
-p 2000:2000 \
-v ~/bunkerm-certs/ca.crt:/etc/mosquitto/certs/ca.crt:ro \
-v ~/bunkerm-certs/server.crt:/etc/mosquitto/certs/server.crt:ro \
-v ~/bunkerm-certs/server.key:/etc/mosquitto/certs/server.key:ro \
-v mosquitto_data:/var/lib/mosquitto \
-v mosquitto_conf:/etc/mosquitto \
bunkeriot/bunkerm:latest Port 8883 is the standard MQTT-over-TLS port.
Step 3: Configure Mosquitto for TLS
Add a TLS listener to your Mosquitto configuration. If you are using a persistent config volume, edit the config file on the host, or mount a custom config snippet:
# /etc/mosquitto/conf.d/tls.conf
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
tls_version tlsv1.2
require_certificate false Set require_certificate true if you want mutual TLS (clients must present a certificate too). For most setups, false is correct - clients verify the server certificate but authenticate with username/password.
Step 4: Restart the Container
docker restart bunkerm Check the logs to confirm Mosquitto started successfully on port 8883:
docker logs bunkerm | grep 8883 Step 5: Connect an MQTT Client with TLS
Your clients now need to trust your CA certificate and connect on port 8883. Example with mosquitto_pub:
mosquitto_pub \
--cafile ~/bunkerm-certs/ca.crt \
-h your-broker-hostname \
-p 8883 \
-u your-username \
-P your-password \
-t test/topic \
-m "hello tls" For other MQTT clients (MQTT Explorer, Paho, etc.), load the ca.crt file as the trusted CA in the TLS settings.
Common Errors
- Certificate verify failed - the client does not trust the CA. Make sure the client has
ca.crtloaded. - SSL handshake error - hostname mismatch between the certificate CN and the broker address used by the client. Regenerate the certificate with the correct CN, or add a SAN (Subject Alternative Name).
- Connection refused on 8883 - confirm the TLS listener is configured and the container exposes port 8883.
- Expired certificate - certificates have a validity period. Renew them before expiry and restart the broker.
Using Let's Encrypt
If your BunkerM instance is accessible from the internet with a real domain name, you can use Let's Encrypt for a trusted certificate. Run Certbot on your host and mount the resulting fullchain.pem and privkey.pem files into the container in place of the self-signed files. Set cafile to an empty string (not needed for publicly trusted CAs).