Skip to main content

Certbot – Let's Encrypt TLS solution for Mosquitto MQTT broker

Proof of Concept

Retrospective Review

VersionModified ByDateChanges Made
v1.0Candice Smith03/09/2024Document Creation draft steps for MQTT Server TLS Implementation
v2.0Shalom Ingabo05/09/2024Updated all process steps with confirmed process and added screenshots following technical PoC.
v3.0Candice Smith05/09/2024Final formatting of document including division of testing categories, Out of Scope items, etc.
v4.0Candice Smith20/09/2024Added Manik’s script

Steps taken and validated during PoC

Set Up Test Environment

Step 1: Set up EC2 instance

Created a new security group to allow inbound rules for SSH, HTTPS and MQTT (1883 for secure MQTT and 8883 for non-secure MQTT). Since it was only for test purposes, I allowed access source from any IP address, however, in the case of production, this needs to be hardened through IP address access control to allow only the necessary IP addresses for security purposes.

Launch instance and connect via SSH using command:

ssh –i /path/to/your-key.pem ubuntu@<EC2-Public-IP>

Step 2: Link your Domain to the instance

Created a domain using AWS called tlsoluttions.com

We used Route 53 on AWS to create a hosted zone for our domain tlsoluttions.com and did some configurations on the A record to point to our running cloud server instance

Tested domain link using domainchecker to ensure that our domain was being hosted using the IP address of the running instance (takes about 60 seconds for changes to be applied.)

Set Up Test Mosquitto Broker

Step 3: Install mosquitto

Run the commands:

sudo apt update
sudo apt install mosquitto mosquitto-clients

in our running instance. This commands updates and install the mosquitto broker to support the MQTT protocol

Step 4: Configure mosquitto for tls

Edited the mosquitto configurations file to support secure connections by running the command:

sudo nano /etc/mosquitto/conf.d/default.conf

Add the following code to enable TLS:

listener 8883

cafile /etc/letsencrypt/live/mqttserver.domain.com/chain.pem

certfile /etc/letsencrypt/live/mqttserver.domain.com/fullchain.pem

keyfile /etc/letsencrypt/live/mqttserver.domain.com/privkey.pem

tls_version tlsv1.2

Explanation of the above code

listener 8883 specifies the port for TLS connections (default is 8883 for TLS).

cafile points to the CA certificate file (part of the Let's Encrypt chain).

certfile points to your server certificate.

keyfile points to your private key.

tls_version specifies the minimum TLS version to use.

Saved the file then restarted mosquitto using command:

sudo systemctl restart mosquito

Set Up Certbot and Let’s Encrypt Solution

Step 5: Install Certbot for Let’s Encrypt TLS Certificates with Apache

Install Certbot and Apcahe plugin using command

Sudo apt install certbot python3-certbot-apache –y

Obtain SSL Certificates using certbot by running the command:

sudo certbot –apache –d tlsoluttions.com -d www.tlsoluttions.com 

[successful certificate generation]

In the above command, certbot uses the Apache plugin to automaticallly configure SSL for our site. Certbot will ask you to choose whether you want to redirect HTTP traffic to HTTPS (which is recommended)

Verify Apache SSL configurations by running the command :

sudo nano /etc/apache2/sites-available/000-default-le-ssl.conf

You should be able to see the following lines which tells Apache to use Let’s Encrypt certificates for your domain

Restart Apache to ensure all changes take effect by running the command:

sudo systemctl restart apache2

Step 6: Set up automatic renewal

To force certbot to renew the certificate every day, you can create a cron job that attempts to renew the certificate everyday by running the command:

sudo crontab -e

Add the following line

Explanation of the line

30 2 * * *: This schedules the task to run at 2:30 AM everyday

/usr/bin/certbot renew –force-renewal

This command forces certbot to renew the certificate, even if it has not reached the typical renewal period which is typically 90 days

/var/log/le-renew.log

This appends the output of the command to a log file for review

To check the list of the active timer, run command:

sudo systemctl list-timers and check for certbot.timer

Step 7: Testing automatic renewal

Let’s Encrypt certificates are valid for 90 days, but with the installation of certbot, the renewal process is automated and can be tested by running the command:

sudo certbot renew –dry-run

[successful automated renewal]

[verifying Apache SSL]

Automation – Script

Setup Automation

To streamline the deployment and configuration process, this is an automated script that sets up Mosquitto, configures TLS, installs Certbot, and manages SSL certificates. Below is the script used for this PoC:

The script-

#!/bin/bash

sudo apt-get update

sudo apt-get install -y mosquitto mosquitto-clients apache2 certbot python3-certbot-apache

sudo tee /etc/mosquitto/conf.d/mosquitto_tls.conf > /dev/null <<EOF

listener 8883

cafile /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem

certfile /etc/letsencrypt/live/YOUR_DOMAIN/cert.pem

keyfile /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem

tls_version tlsv1.2

EOF

sudo a2enmod proxy proxy_http proxy_wstunnel ssl

sudo tee /etc/apache2/sites-available/000-default.conf > /dev/null <<EOF

<VirtualHost *:80>

ServerName YOUR_DOMAIN

ProxyPass /mqtt ws://localhost:1883/

ProxyPassReverse /mqtt ws://localhost:1883/

ProxyPass /mqttssl wss://localhost:8883/

ProxyPassReverse /mqttssl wss://localhost:8883/

ErrorLog \${APACHE_LOG_DIR}/error.log

CustomLog \${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

EOF

sudo systemctl restart apache2

sudo certbot --apache -d YOUR_DOMAIN

sudo mkdir -p /etc/mosquitto/certs

sudo cp /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem /etc/mosquitto/certs/fullchain.pem

sudo cp /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem /etc/mosquitto/certs/privkey.pem

echo "0 3 * * * certbot renew --post-hook 'systemctl restart apache2 && systemctl restart mosquitto'" | sudo tee -a /var/spool/cron/crontabs/root

Steps to use the script

Create a new file for the script:

nano new_file.sh

Paste the automated script into the file. Make sure to replace YOUR_DOMAIN with your actual domain name

Change the script’s permissions to make it executable:

sudo chmod +x new_file.sh

Execute the script to perform the setup:

sudo ./new_file.sh

Out of Scope

Additional steps and information that may be useful during implementation, deemed out of scope for PoC activity.

Alternative Certbot installation methods for various OS’s can be found here:  

Verify config by testing with MQTT Clients

mosquitto_sub -h mqttserver.domain.com -p 8883 -t test/topic \--cafile

/etc/letsencrypt/live/mqttserver.domain.com/chain.pem

*You may need to adjust the port -- please review

In the case a client fails to connect, check Mosquitto logs for errors.

sudo journalctl -u mosquito

Reload Mosquitto config after successful renewal:

sudo nano /etc/letsencrypt/renewal-hooks/post/reload-mosquitto.sh
#!/bin/bash
systemctl reload mosquitto
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/reload-mosquitto.sh

Proof of Concept Outcome

The outcome of this PoC has been to validate the process for the successful deployment of Certbot and Let’s Encrypt to secure a Mosquitto MQTT broker stored on a server utilising Apache as the operating system.

Not only does this provide a validated process for future TLS deployments but also provides a guide to creating a testing environment for any future proof of concept requirements resulting in a much more efficient process and more focus on testing the new technologies rather than the testing environment.

This PoC has resulted in the successful testing of the Certbot – Let's Encrypt TLS solution as applied to our test MQTT broker, with the successful renewal of the deployed certificate. All this is also captured in an easy to run script which will deploy a Mosquitto broker with TLS.