How to Install and Secure the Mosquitto MQTT Messaging Broker on Ubuntu 20.04
Mosquitto is an open-source message broker that uses the Message Queuing Telemetry Transport (MQTT) Protocol. The protocol is designed to provide lightweight communication to the Internet of Things (IoT) devices. It is commonly used for GPS tracking of vehicles, home automation, environmental sensors, and large-scale data collection.
The MQTT protocol runs on top of the TCP/IP model. Being lightweight, its small code footprint allows you to create applications for devices with minimal resources. It relies on the publish/subscribe model. In this model, the client connects to the Mosquitto server, which acts as a broker to send information to other clients subscribed to a channel.
In this tutorial, you will install Mosquitto and set up the broker to use SSL to protect communications.
Prerequisites
- An Ubuntu 20.04 server with a non-root user with sudo privileges.
- A domain name (
myqtt.example.com
) pointed at your server.
Step 1 - Install Mosquitto Server and Client
Ubuntu ships with the older 1.6 version of Mosquitto. To install the latest version, add the official Mosquitto repository.
$ sudo add-apt-repository ppa:mosquitto-dev/mosquitto-ppa
Install the Mosquitto server and the client.
$ sudo apt install mosquitto mosquitto-clients
Check the status of the server.
$ sudo systemctl status mosquitto ? mosquitto.service - Mosquitto MQTT Broker Loaded: loaded (/lib/systemd/system/mosquitto.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2022-01-25 09:18:40 UTC; 25s ago Docs: man:mosquitto.conf(5) man:mosquitto(8) Main PID: 119694 (mosquitto) Tasks: 1 (limit: 2274) Memory: 1.0M CGroup: /system.slice/mosquitto.service ??119694 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf Jan 25 09:18:39 <userid> systemd[1]: Starting Mosquitto MQTT Broker... Jan 25 09:18:40 <userid> systemd[1]: Started Mosquitto MQTT Broker.
Step 2 - Configure MQTT Password Authentication
Mosquitto comes with a utility to generate a password file called mosquitto_passwd
. Mosquitto stores all the configurations in the /etc/mosquitto
directory.
Run the following command to generate an encrypted password file at /etc/mosquitto/passwd
for the username username
. Enter a password of your choice.
$ sudo mosquitto_passwd -c /etc/mosquitto/passwd username Password: Reenter password:
Next, create a default.conf
file under the /etc/mosquitto/conf.d
directory and open it for editing.
$ sudo nano /etc/mosquitto/conf.d/default.conf
Paste the following lines to specify the location of the password file. If you omit the listener field, it will always connect anonymously, irrespective of the configuration.
listener 1883 password_file /etc/mosquitto/passwd
Save the file by pressing Ctrl + X and entering Y when prompted.
Restart the Mosquitto server to implement the change.
$ sudo systemctl restart mosquitto
Step 3 - Test Mosquitto Client
Depending on the use case, you can use the Mosquitto client to send and receive messages on different topics. A client is either a subscriber or publisher.
The next step is to subscribe to a topic. In the MQTT protocol, a topic refers to a string used by the server/broker to filter messages for the connected clients. Here are some sample topics you can use in a home automation application.
- home/lights/sitting_room
- home/lights/kitchen
- home/lights/master_bedroom
- home/lights/kids_bedroom
To subscribe to a topic, run the mosquitto_sub -t
command followed by the topic. For example, to subscribe to home/lights/kitchen
topic, run the following command.
$ mosquitto_sub -u username -P YOUR_PASSWORD -t "home/lights/kitchen"
Don't close the existing window. Open a new terminal window to publish a message to the home/lights/kitchen
topic using the following command.
$ mosquitto_pub -u username -P YOUR_PASSWORD -m "ON" -t "home/lights/kitchen"
Go back to the first terminal window, and you will receive ON
payload.
ON
Next, send the OFF
message on the same topic from the second terminal.
$ mosquitto_pub -u username -P YOUR_PASSWORD -m "OFF" -t "home/lights/kitchen"
The first terminal will show the newly published message.
ON OFF
If you try to send an unauthenticated comment, it will fail. For example, try the following command.
$ mosquitto_sub -t "home/lights/sitting_room" Connection error: Connection Refused: not authorised.
It is not recommended, but you need to add the following line to the /etc/mosquitto/conf.d/default.conf
file if you want to run the commands without authentication.
allow_anonymous true
Step 4 - Install SSL
To install an SSL certificate using Let's Encrypt, we need to download the Certbot tool. We will use the Snapd package installer for that.
Install Snap installer.
$ sudo apt install snapd
Ensure that your version of Snapd is up to date.
$ sudo snap install core $ sudo snap refresh core
Install Certbot.
$ sudo snap install --classic certbot
Use the following command to ensure that the Certbot command runs by creating a symbolic link to the /usr/bin
directory.
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Generate an SSL certificate.
$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d mqtt.example.com
The above command will download a certificate to the /etc/letsencrypt/live/mqtt.example.com
directory on your server.
Generate a Diffie-Hellman group certificate.
$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
Create a challenge web root directory for Let's Encrypt auto-renewal.
$ sudo mkdir -p /var/lib/letsencrypt
Create a Cron Job to renew the SSL. It will run every day to check the certificate and renew if needed. For that, first, create the file /etc/cron.daily/certbot-renew
and open it for editing.
$ sudo nano /etc/cron.daily/certbot-renew
Paste the following code.
#!/bin/sh certbot renew --cert-name mqtt.example.com --webroot -w /var/lib/letsencrypt/
Save the file by pressing Ctrl + X and entering Y when prompted.
Change the permissions on the task file to make it executable.
$ sudo chmod +x /etc/cron.daily/certbot-renew
Step 5 - Configure MQTT SSL
Now that we have the SSL certificates ready, we need to provide Mosquitto access to them. For this, we need to copy the certificates to a location from where Mosquitto can access them.
$ sudo cp /etc/letsencrypt/live/mqtt.example.com/fullchain.pem /etc/mosquitto/certs/server.pem $ sudo cp /etc/letsencrypt/live/mqtt.example.com/privkey.pem /etc/mosquitto/certs/server.key
Change the ownership of the /etc/mosquitto/certs
directory to the mosquitto
user created during the installation.
$ sudo chown mosquitto: /etc/mosquitto/certs
The next step to enable the SSL encryption for Mosquitto is to specify the location of the SSL certificates. Open the configuration file for editing.
$ sudo nano /etc/mosquitto/conf.d/default.conf
Paste the following code at the end of the file.
. . . listener 8883 certfile /etc/mosquitto/certs/server.pem cafile /etc/ssl/certs/ISRG_Root_X1.pem keyfile /etc/mosquitto/certs/server.key dhparamfile /etc/ssl/certs/dhparam.pem
Save the file by pressing Ctrl + X and entering Y when prompted. Be sure to leave a trailing newline at the end of the file.
The listener 8883
portion sets up the encrypted listener. It is the standard port for MQTT + SSL, referred to as MQTTS. The next four lines specify the location of the SSL files.
Restart Mosquitto to update the settings.
$ sudo systemctl restart mosquitto
You will need to update the firewall to allow connections to port 8883.
$ sudo ufw allow 8883
Next, we need to test the functionality using the mosquitto_pub
command.
$ mosquitto_pub -h mqtt.example.com -t "home/lights/kitchen" -m "hello" -p 8883 --capath /etc/ssl/certs/ -u username -P YOUR_PASSWORD
As you can see, we have included certain additional parameters, including the port number and the path to the SSL certificates. Whenever you need to use SSL, you will always have to specify the full hostname, i.e., mqtt.example.com
instead of localhost
otherwise, it would give an error.
You will also need to add the --capath
directive every time. It tells the Mosquitto client to look for root certificates installed by the operating system.
Step 6 - Configure SSL Renewal
Certbot will automatically renew your certificate before it expires. But it needs to be told to copy the renewed certificates to the /etc/mosquitto/certs
directory and restart Mosquitto service.
We are going to do that by creating a shell script. Create a file mosquitto-copy.sh
in the /etc/letsencrypt/renewal-hooks/deploy
directory.
$ sudo nano /etc/letsencrypt/renewal-hooks/deploy/mosquitto-copy.sh
Paste the following code in it. Replace the value of the MY_DOMAIN
variable with your domain. The ${RENEWED_LINEAGE}
variable points to the /etc/letsencrypt/live/mqtt.example.com
directory during renewal.
# Set which domain this script will be run for MY_DOMAIN=mqtt.example.com # Set the directory that the certificates will be copied to. CERTIFICATE_DIR=/etc/mosquitto/certs if [ "${RENEWED_DOMAINS}" = "${MY_DOMAIN}" ]; then # Copy new certificate to Mosquitto directory cp ${RENEWED_LINEAGE}/fullchain.pem ${CERTIFICATE_DIR}/server.pem cp ${RENEWED_LINEAGE}/privkey.pem ${CERTIFICATE_DIR}/server.key # Set ownership to Mosquitto chown mosquitto: ${CERTIFICATE_DIR}/server.pem ${CERTIFICATE_DIR}/server.key # Ensure permissions are restrictive chmod 0600 ${CERTIFICATE_DIR}/server.pem ${CERTIFICATE_DIR}/server.key # Tell Mosquitto to reload certificates and configuration pkill -HUP -x mosquitto fi
Save the file by pressing Ctrl + X and entering Y when prompted.
Make the file executable.
$ sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/mosquitto-copy.sh
This script will be automatically run on every successful renewal of the certificate.
If you are running Mosquitto and a web server like Nginx, you need to instruct Certbot to stop the server before renewal and start it again once finished. To do that, open the file etc/letsencrypt/renewal/mqtt.example.com.conf
.
$ sudo nano /etc/letsencrypt/renewal/mqtt.example.com.conf
Add the following lines at the end of the file. Change the commands accordingly to the webserver you are using.
pre_hook = systemctl stop nginx post_hook = systemctl start nginx
Save the file by pressing Ctrl + X and entering Y when prompted.
Run a Certbot dry run to verify.
$ sudo certbot renew --dry-run
If you see no errors, it means everything is set.
Step 7 - Configure Websockets
You can configure Mosquitto to use the MQTT protocol from within browsers using Javascript using the Websockets functionality. To enable it, open the configuration file.
$ sudo nano /etc/mosquitto/conf.d/default.conf
Paste the following lines at the end of the file.
. . . listener 8083 protocol websockets certfile /etc/mosquitto/certs/server.pem cafile /etc/ssl/certs/ISRG_Root_X1.pem keyfile /etc/mosquitto/certs/server.key dhparamfile /etc/ssl/certs/dhparam.pem
Save the file by pressing Ctrl + X and entering Y when prompted.
If you notice, it is the same block as the one we used for enabling SSL except for the port number and protocol fields. 8083 is the most common port used by MQTT to talk using WebSockets.
Restart the Mosquitto service.
$ sudo systemctl restart mosquitto
Open port 8083.
$ sudo ufw allow 8083
We need to use a browser-based MQTT client to test the WebSockets functionality. There are a lot of clients available, but we will use the HiveMQ Websocket client for our purpose. Launch the client in your browser, and you will see the following.
As shown in the screenshot above, fill the fields as shown.
- The host should be the domain of your Mosquitto server, mqtt.example.com.
- Port should be 8083.
- ClientID field can be left as it is.
- The username should be your Mosquitto username.
- Password should be the password you created above.
- Check the SSL box.
Press the Connect button, and the HiveMQ client will be connected to your Mosquitto server.
Once connected, enter home/lights/kitchen
as the topic, enter any message and press Publish.
The message will show up in your mosquitto_sub
terminal window confirming the successful connection.
This shows that the Websockets implementation is successful.
Conclusion
This concludes our setup of a secure, password-protected, and SSL-encrypted MQTT server on a Ubuntu 20.04 based machine. If you have any questions, post them in the comments below.