I am trying to connect to the MQTT Broker using MQTT.js in my React application, but I am getting an error with the WSS protocol.
First, my mosquitto.conf file:
# mosquitto.conf
pid_file /run/mosquitto/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
log_dest file /var/log/mosquitto/mosquitto.log
include_dir /etc/mosquitto/conf.d
allow_anonymous false
password_file /etc/mosquitto/passwd
listener 3940
protocol mqtt
listener 39393
protocol websockets
listener 3941
protocol mqtt
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/broker.crt
keyfile /etc/mosquitto/certs/broker.key
listener 3942
protocol websockets
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/broker.crt
keyfile /etc/mosquitto/certs/broker.key
And the code block in my React application:
// some.jsx
useEffect(() => {
let reconnectAttempts = 0;
try {
if (user && !client) {
const host = "ws://my.domain.io:39393"
// const host = "wss://my.domain.io:3942
const options = {
keepalive: 60,
clientId: `${user.username}_${user.id}_${user.tenant}_${Date.now()}`,
username: "username",
password: "password",
clean: true,
rejectUnauthorized: false
};
const mqttClient = mqtt.connect(host, options);
setClient(mqttClient);
console.log("client: ", mqttClient);
mqttClient.on("connect", () => {
console.log("Connected to MQTT broker");
setIsConnected(true);
setIsReconnecting(false);
setIsDisconnected(false);
reconnectAttempts = 0;
});
mqttClient.on("disconnect", () => {
console.log("Disconnected to MQTT broker");
setIsConnected(false);
setIsDisconnected(true);
});
mqttClient.on("close", (err) => {
console.log("Closed connection to MQTT broker", err);
});
mqttClient.on("reconnect", () => {
reconnectAttempts++;
setIsReconnecting(true);
if (reconnectAttempts > 5) {
mqttClient.end();
console.log("Reconnect attempts exceeded. Closing connection to MQTT broker");
setIsConnected(false);
setIsDisconnected(true);
return;
}
console.log("Reconnecting to MQTT broker", reconnectAttempts);
});
mqttClient.on("error", (err) => {
console.log("Error from MQTT broker", err);
});
}
} catch (error) {
console.error("Error connecting to MQTT broker", error);
}
return () => {
if (client) {
console.log("MQTT Hook cleanup")
client.end();
setClient(null);
}
}
}, [user, client]);
I can connect to the host mqtts://my.domain.io:3941
on my local device, but I cannot connect to the host wss://my.domain.io:3942
in the production environment because I need to connect via HTTPS. Additionally, I can connect to wss://my.domain.io:3942
and perform pub/sub operations without any issues using Python, MQTT Box, and MQTT Explorer.
UPDATE:
# some.py
def connect(self):
self.client.on_message = self.on_message
self.client.on_connect = self.on_connect
self.client.on_disconnect = self.on_disconnect
self.client.tls_set(cert_reqs=ssl.CERT_NONE)
self.client.username_pw_set(self.username, self.password)
self.client.connect(self.broker, self.port, keepalive=10)
self.client.loop_start()
My Mosquitto logs are as follows. My backend application running in the local environment can connect to the port 3941 without a certificate, while my React application can only connect to the port 39393 without a certificate.
When my React application in the production environment tries to connect to port 39393, my console shows:
When it tries to connect to port 3942, my console shows:
Lastly, even though my React application is set to either port 39393 or 3942 in the production environment, no data appears in my Mosquitto logs.
So I want connect React to MQTT over WSS in my production server.
I had an issue where I couldn't connect to a secure MQTT broker at wss://dash.meetlarry.io:3942 over HTTPS while on a React Linux server. The steps I followed to solve this issue are as follows:
First, I modified the Nginx configuration files to include the MQTT configuration, as the React server already had configurations for the certificates:
# React App Server
server {
server_name my.domain.io;
root /var/www/html/app/build;
index index.html;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/my.domain.io/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/my.domain.io/privkey.pem;
location / {
try_files $uri /index.html;
}
location /mqtt {
proxy_pass http://localhost:39393; # Mosquitto WebSocket port
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
# Redirect HTTP to HTTPS for React App
server {
listen 80;
server_name my.domain.io;
return 301 https://$host$request_uri;
}
Then, I updated the code within React as follows:
const options = {
host: "my.domain.io", // current server name with certificate
port: 443, // port listened by nginx
path: '/mqtt', // location assigned in nginx
protocol: 'wss', // protocol
keepalive: 60,
clientId: `${user.username}_${user.id}_${user.tenant}_${Date.now()}`,
username: "username",
password: "password",
rejectUnauthorized: false
};
const mqttClient = mqtt.connect(options);
setClient(mqttClient);
Next, I updated the MQTT configurations on the DRF side:
class MQTTClient:
def __init__(self, broker, port, username, password):
self.broker = broker
self.port = port
self.username = username
self.password = password
client_id = f"larry_hotline-{random.randint(0, 1000)}"
self.client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id, transport="websockets")
def connect(self):
self.client.on_message = self.on_message
self.client.on_connect = self.on_connect
self.client.on_disconnect = self.on_disconnect
self.client.tls_set(cert_reqs=ssl.CERT_NONE)
self.client.username_pw_set(self.username, self.password)
self.client.connect(self.broker, self.port, keepalive=10)
self.client.loop_start()
I ran my Django application on the 3942 WebSocket port to ensure messages are transmitted, and this solved the strange issue.
The reason I resorted to this solution is that I tried to certificate the IP address of my MQTT broker and connect by entering this IP address instead of the domain name through MQTT.js, but both attempts failed. I would have preferred to create a specific certificate for the MQTT broker and connect with MQTT.js directly. If anyone has managed to connect in this way before, I would be very happy if they could explain this method to me as well :)