How to setup a secured MQTT broker
What is MQTT?
“MQTT(MQ Telemetry Transport) is a machine-to-machine (M2M)/IOT connectivity protocol.”
MQTT is a extremely light weight publisher/subscriber messaging protocol. Constrained Application Protocol (CoAP) and Advanced Message Queuing Protocol (AMQP) are two of the MQTT replaceable transport protocols.
MQTT broker is the intermediate handler of all the messages. It can handle up to thousands of clients concurrently. It is responsible for receiving all messages, filtering those messages, determining who is subscribed to each message, and sending the message to those subscribed clients.
For a MQTT broker you have two options. Either you can use an online broker or setup a local MQTT broker. In here we are going to setup an own MQTT broker. It may be on a Raspberry pi ,on a virtual machine on cloud (AWS, DO etc.) or on your own machine (not preferred).
Mosquitto is a popular open source message broker that has great community support. As it is easy to install and configure, we are going to use it here. From this comparison you can find out a message broker that fits to your requirements.
Requirements:
- A raspberry pi or virtual machine on cloud
- A domain name pointed at your server
Step 1 — Installing Mosquitto broker
First install software packages for Mosquitto.
sudo apt-get update
sudo apt install mosquitto mosquitto-clients
After installation, Mosquitto service will start automatically.
Step 2 — Configuring MQTT usernames and passwords
In Mosquitto software package, there is a utility called mosquitto_passwd
to generate specific password file.
sudo mosquitto_passwd -c /etc/mosquitto/passwd your-username
This will prompts to enter a password. This specific username and password will be stored at /etc/mosquitto/passwd
After that we’ll have to create a new configuration file for Mosquitto.
sudo nano /etc/mosquitto/conf.d/default.conf
This will open up an empty file using nano command-line editor. Add following lines and save the file.
allow_anonymous false
password_file /etc/mosquitto/passwd
Making allow_anonymous
to false
will permit only authenticated users to connect to the broker. password_file
directs where to find the password file.
Now to apply changes, we have to restart the mosquitto service
sudo systemctl restart mosquitto
We can test this setup by subscribing to the ‘test’ topic and publishing to it.
mosquitto_sub -h localhost -t test -u “your-username” -P “your-password”
Now publish “hello world” to the ‘test’ topic on another terminal window.
mosquitto_pub -h localhost -t test -m “hello world” -u “your-username” -P “your-password”
If you can see “hello world” on the subscribed terminal window then you have successfully configured username password authentication for Mosquitto. Due to unencrypted information exchange still the connection is not secure.
Step 3 — Securing MQTT with SSL
To secure MQTT connection with SSL, we need SSL certificates. Let’s Encrypt is a certificate authority which offers free SSL certificates. In order to have SSL certificates from this service you should have a domain name pointed at your MQTT server.
Installing Certbot
Certbot is the official Let’s Encrypt client. First, we have to add Certbot repository to download latest version of it.
sudo add-apt-repository ppa:certbot/certbot
Then we should update the package list. After that we can install Certbot.
sudo apt-get update
sudo apt-get install certbot
Fetching SSL certificates through Certbot
Cerbot uses port 80 to speak with the Let’s encrypt API. Therefore we should open the port 80 in firewall.
sudo ufw allow 80
Then run Cerbot with the following command. Here you have to replace mqtt.example.com
with your domain name.
sudo certbot certonly --standalone --preferred-challenges http -d mqtt.example.com
This will ask for your email address. Finally, the certificates will be stored at /etc/letsencrypt/live/mqtt.example.com
directory.
Configuring Mosquitto SSL
Open previously created Mosquitto configuration file to add SSL configurations.
sudo nano /etc/mosquitto/conf.d/default.conf
Add following lines by replacing mqtt.example.com
with your domain name.
listener 1883 localhost
listener 8883
certfile /etc/letsencrypt/live/mqtt.example.com/cert.pem
cafile /etc/letsencrypt/live/mqtt.example.com/chain.pem
keyfile /etc/letsencrypt/live/mqtt.example.com/privkey.pem
listener 8083
protocol websockets
certfile /etc/letsencrypt/live/mqtt.example.com/cert.pem
cafile /etc/letsencrypt/live/mqtt.example.com/chain.pem
keyfile /etc/letsencrypt/live/mqtt.example.com/privkey.pem
- Standard unencrypted port for MQTT is
1883
. First, we are makinglocalhost
as the listener for that port. So this port is not externally accessible. - Port
8883
is the standard MQTT port over SSL also called asMQTTS
. Here we are giving paths to thecertfile
,cafile
andkeyfile
of the fetched Let’s encrypt files. - Finally, we have make port
8083
for MQTT over websockets.
Now we should open 8883
and 8083
ports from firewall.
sudo ufw allow 8883
sudo ufw allow 8083
To apply configurations, Mosquitto service should be restart again.
sudo systemctl restart mosquitto
Configure to restart Mosquitto service on certificate renewal
Let’s encrypt certificates are valid only for 90 days. Certbot client will automatically renew these certificates before they expire. But we have to configure Certbot to restart Mosquitto service after the renewal of the certificates.
Open the Certbot renewal configuration file using nano command-line editor by replacing mqtt.example.com
in the file name with your domain name.
sudo nano /etc/letsencrypt/renewal/mqtt.example.com.conf
Add the following at the end of the configuration file and save it.
renew_hook = systemctl restart mosquitto
You can run Certbot dry run and make sure there are no errors.
sudo certbot renew --dry-run
Step 4 — Testing secured Mosquitto MQTT broker over SSL
Testing secure SSL connection on port 8883
Finally, we can test our broker as we did before. Subscribe to ‘test’ topic by giving path to the root certificates which were installed by the operating system. Here you have to give username and password we created in step 2 and replace mqtt.example.com
with your domain name.
mosquitto_sub -h mqtt.example.com -t test -p 8883 --capath /etc/ssl/certs/ -u "your-username" -P "your-password"
Now publish “hello word” from another terminal window.
mosquitto_pub -h mqtt.example.com -t test -m "hello world" -p 8883 --capath /etc/ssl/certs/ -u "your-username" -P "your-password"
Testing MQTT over websockets
You can test MQTT over websockets using Eclipse Paho JavaScript client Utility.
After connecting you can subscribe and publish to topics.