Skip to main content

Overview

Secure WebSocket (WSS) adds TLS encryption to WebSocket connections, protecting MQTT traffic in browser and web applications. The standard port is 443 (HTTPS) or a custom port like 8443.

Configuration

Basic Secure WebSocket Listener

config.xml
<hivemq>
  <listeners>
    <tls-websocket-listener>
      <port>8443</port>
      <bind-address>0.0.0.0</bind-address>
      <path>/mqtt</path>
      <name>secure-websocket-listener</name>
      <tls>
        <keystore>
          <path>/opt/hivemq/conf/keystore.jks</path>
          <password>keystore-password</password>
          <private-key-password>key-password</private-key-password>
        </keystore>
      </tls>
    </tls-websocket-listener>
  </listeners>
</hivemq>

With Client Certificate Authentication

<tls-websocket-listener>
  <port>8443</port>
  <bind-address>0.0.0.0</bind-address>
  <path>/mqtt</path>
  <tls>
    <keystore>
      <path>/opt/hivemq/conf/keystore.jks</path>
      <password>keystore-password</password>
      <private-key-password>key-password</private-key-password>
    </keystore>
    <truststore>
      <path>/opt/hivemq/conf/truststore.jks</path>
      <password>truststore-password</password>
    </truststore>
    <client-authentication-mode>REQUIRED</client-authentication-mode>
    <protocols>
      <protocol>TLSv1.2</protocol>
      <protocol>TLSv1.3</protocol>
    </protocols>
  </tls>
</tls-websocket-listener>

Browser Client Example

MQTT.js with WSS

<!DOCTYPE html>
<html>
<head>
  <title>Secure MQTT WebSocket</title>
  <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
</head>
<body>
  <h1>Secure MQTT WebSocket Client</h1>
  <div id="status">Disconnected</div>
  <div id="messages"></div>
  
  <script>
    // Connect via Secure WebSocket (WSS)
    const client = mqtt.connect('wss://broker.example.com:8443/mqtt', {
      clientId: 'web_secure_' + Math.random().toString(16).substr(2, 8),
      username: 'user',
      password: 'pass',
      keepalive: 60,
      clean: true,
      reconnectPeriod: 5000
    });
    
    client.on('connect', () => {
      document.getElementById('status').innerHTML = 'Connected (Secure)';
      client.subscribe('secure/messages', { qos: 1 });
    });
    
    client.on('message', (topic, message) => {
      const msg = message.toString();
      const div = document.getElementById('messages');
      div.innerHTML += `<p>${topic}: ${msg}</p>`;
    });
    
    client.on('error', (error) => {
      console.error('Error:', error);
      document.getElementById('status').innerHTML = 'Error';
    });
  </script>
</body>
</html>

Node.js with WSS

const mqtt = require('mqtt');
const fs = require('fs');

// With CA certificate
const client = mqtt.connect('wss://broker.example.com:8443/mqtt', {
  clientId: 'nodejs_secure_client',
  ca: fs.readFileSync('/path/to/ca.crt'),
  rejectUnauthorized: true
});

client.on('connect', () => {
  console.log('Connected securely via WSS');
});

With Client Certificate

const client = mqtt.connect('wss://broker.example.com:8443/mqtt', {
  clientId: 'nodejs_mutual_tls',
  ca: fs.readFileSync('/path/to/ca.crt'),
  cert: fs.readFileSync('/path/to/client.crt'),
  key: fs.readFileSync('/path/to/client.key'),
  rejectUnauthorized: true
});

Using Port 443 (HTTPS)

For better firewall compatibility, run WSS on port 443:
<tls-websocket-listener>
  <port>443</port>
  <bind-address>0.0.0.0</bind-address>
  <path>/mqtt</path>
  <tls>
    <keystore>
      <path>/opt/hivemq/conf/keystore.jks</path>
      <password>keystore-password</password>
      <private-key-password>key-password</private-key-password>
    </keystore>
  </tls>
</tls-websocket-listener>
Running on port 443 may require root privileges or port forwarding. In Docker, map host port 443 to container port 8443.

Docker Configuration

# Map to standard HTTPS port
docker run -d --name hivemq-ce \
  -p 1883:1883 \
  -p 443:8443 \
  -v /path/to/keystore.jks:/opt/hivemq/conf/keystore.jks \
  hivemq/hivemq-ce

Let’s Encrypt with WSS

Generate Keystore from Let’s Encrypt

# Convert Let's Encrypt certificates to PKCS12
openssl pkcs12 -export \
  -in /etc/letsencrypt/live/broker.example.com/fullchain.pem \
  -inkey /etc/letsencrypt/live/broker.example.com/privkey.pem \
  -out keystore.p12 \
  -name hivemq \
  -passout pass:changeit

# Convert PKCS12 to JKS
keytool -importkeystore \
  -srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass changeit \
  -destkeystore keystore.jks -deststoretype JKS -deststorepass changeit

Auto-Renewal Script

#!/bin/bash
# renew-cert.sh

certbot renew

# Convert to JKS
openssl pkcs12 -export \
  -in /etc/letsencrypt/live/broker.example.com/fullchain.pem \
  -inkey /etc/letsencrypt/live/broker.example.com/privkey.pem \
  -out /opt/hivemq/conf/keystore.p12 \
  -name hivemq -passout pass:changeit

keytool -importkeystore \
  -srckeystore /opt/hivemq/conf/keystore.p12 -srcstoretype PKCS12 -srcstorepass changeit \
  -destkeystore /opt/hivemq/conf/keystore.jks -deststoretype JKS -deststorepass changeit -noprompt

# Restart HiveMQ
systemctl restart hivemq

Reverse Proxy Setup

Nginx as WSS Proxy

server {
    listen 443 ssl;
    server_name broker.example.com;
    
    ssl_certificate /etc/letsencrypt/live/broker.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/broker.example.com/privkey.pem;
    
    location /mqtt {
        proxy_pass http://localhost:8000/mqtt;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
Then clients connect to:
const client = mqtt.connect('wss://broker.example.com/mqtt');

Firewall Configuration

# Open WSS port (8443)
sudo firewall-cmd --permanent --add-port=8443/tcp
sudo firewall-cmd --reload

# Or for port 443
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Security Best Practices

Valid Certificates

Use certificates from trusted CA for production

TLS 1.2+

Disable TLS 1.0 and 1.1

Strong Ciphers

Configure modern cipher suites

Certificate Monitoring

Set expiration alerts

Troubleshooting

  • Ensure certificate is issued by trusted CA
  • Verify certificate matches domain name
  • Check certificate has not expired
  • For self-signed certs, add exception in browser
  • Check TLS configuration is valid
  • Verify keystore password is correct
  • Ensure certificate file exists and is readable
  • Verify port 8443 or 443 is open
  • Check firewall rules
  • Test with openssl: openssl s_client -connect broker.example.com:8443

Testing WSS Connection

# Test TLS handshake
openssl s_client -connect broker.example.com:8443 -servername broker.example.com

# Test with curl (WebSocket upgrade)
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: test" \
  https://broker.example.com:8443/mqtt

Next Steps

WebSocket (HTTP)

Unencrypted WebSocket transport

TLS TCP

MQTT over TLS

Security Config

Additional security settings

Client Guide

More connection examples

Build docs developers (and LLMs) love