{"id":2161,"date":"2020-06-12T07:49:28","date_gmt":"2020-06-12T04:49:28","guid":{"rendered":"https:\/\/upcloud.com\/global\/us\/resources\/tutorials\/install-secure-mqtt-broker-ubuntu\/"},"modified":"2026-02-12T21:09:59","modified_gmt":"2026-02-12T21:09:59","slug":"install-secure-mqtt-broker-ubuntu","status":"publish","type":"tutorial","link":"https:\/\/upcloud.com\/global\/resources\/tutorials\/install-secure-mqtt-broker-ubuntu\/","title":{"rendered":"How to install secure MQTT broker on Ubuntu"},"content":{"rendered":"<p>MQTT stands for MQ Telemetry Transport. It is a publish\/subscribe, extremely simple and lightweight messaging protocol, designed for constrained devices and low-bandwidth, high-latency or unreliable networks. The MQTT protocol defines two types of network entities: a message broker and a number of clients. An MQTT broker is a server that receives all messages from the clients and then routes the messages to the appropriate destination clients. An MQTT client is any device (from a microcontroller up to a full-fledged server) that runs an MQTT library and connects to an MQTT broker over a network.<\/p>\n<p>In this tutorial, you will learn how to install, configure and secure an MQTT broker. For this task, we will use a popular message broker Mosquitto. In addition, you will learn how to use Certbot to automatically acquire Let\u2019s Encrypt SSL\/TLS certificate for your server. We will show you how to install and configure a simple Node.js web server for monitoring MQTT messages remotely from a web browser. We will also install a MongoDB for storing MQTT messages in the database.<\/p>\n<p><a class=\"button\" href=\"https:\/\/signup.upcloud.com\/\">Test hosting on UpCloud!<\/a><\/p>\n<h2>Prerequisites<\/h2>\n<h4>Domain name<\/h4>\n<p>You will need a valid domain name pointed to your server IP address. If you do not have one, you can purchase it from many domain name seller, e.g. <a href=\"https:\/\/www.namecheap.com\/\" target=\"_blank\" rel=\"noopener\">Namecheap<\/a>, <a href=\"https:\/\/godaddy.com\/\" target=\"_blank\" rel=\"noopener\">GoDaddy<\/a>, <a href=\"https:\/\/www.domain.com\/\" target=\"_blank\" rel=\"noopener\">Domain.com<\/a>, or any other that you prefer. If you do not know how to point a domain name to an IP address, check <a href=\"https:\/\/upcloud.com\/global\/docs\/guides\/domain-name-system\/\" target=\"_blank\" rel=\"noopener\">this guide to domain name systems<\/a> or refer to an instruction from your domain name seller. For the purpose of this tutorial, we will use <span style=\"color: #ff0000;\">mqtt.example.com<\/span> domain name as an example, replace it with your domain where asked.<\/p>\n<h4>Key pair<\/h4>\n<p>You will need to have a key pair to be able to use SSH keys login. If you do not have one, you will need to generate it.<\/p>\n<p>On Linux and macOS open a terminal window. At the shell prompt, type the following command:<\/p>\n<pre>ssh-keygen -t rsa<\/pre>\n<p>The <em>ssh-keygen<\/em> program will prompt you for the location of the key file. You can use the default one or specify your own. Another option is to specify a passphrase to protect your key material. Note the location to which your public and private keys were saved because they will be required later.<\/p>\n<p>On Windows, download and install PuTTY from the <a href=\"https:\/\/www.putty.org\/\" target=\"_blank\" rel=\"noopener\">official website<\/a>. Go to Start &gt; All Programs &gt; PuTTY &gt; PuTTYgen and start the application. Click the Generate button and follow the instructions. Once the key generation is finished, you will be presented with the results. Click Save Private Key to save the private key as a file. Repeat the process for the public key, or simply copy the public key from PuTTY\u2019s text area into your clipboard and save it as a text file. Note the location to which your public and private keys were saved because they will be required later.<\/p>\n<h2>Step 1 &#8211; Deploying a Cloud Server<\/h2>\n<p>First things first, if you are not registered on the UpCloud yet, <a href=\"https:\/\/signup.upcloud.com\/\" target=\"_blank\" rel=\"noopener\">begin by getting signed up<\/a>. Take a moment to create an account after which you can easily <a href=\"https:\/\/hub.upcloud.com\/deploy\/\" target=\"_blank\" rel=\"noopener\">deploy your own cloud servers<\/a>.<\/p>\n<p>Deploy a new cloud instance, where the first Simple Plan of 1 CPU core, 1 GB memory and 25 GB storage is sufficient. Of course, if you are planning to put your Server on some heavy tasks, use another Simple plan or the Flexible one. Select an availability zone of your choice and the Ubuntu Server 18.04 LTS (Bionic Beaver) from the Public Templates. You can find in-depth instructions on all configuration options in a guide for <a href=\"https:\/\/upcloud.com\/global\/docs\/guides\/deploy-server\/\" target=\"_blank\" rel=\"noopener\">how to deploy a server<\/a>.<\/p>\n<h2>Step 2 &#8211; Initial Server Configuration<\/h2>\n<p>In this step, you will find out how to configure your Ubuntu Server for increasing security and usability. This will give you a solid foundation for subsequent actions. You will learn about SSH Keys login, creating a new user with administrative privileges and basic firewall settings. If you already did this during deployment phase with <a href=\"https:\/\/upcloud.com\/global\/docs\/guides\/initialization-scripts\/\" target=\"_blank\" rel=\"noopener\">Initialization Scripts<\/a>, or manually after the deployment phase, you should skip this step.<\/p>\n<p>If you are not already connected to your server, go ahead and log in as the root user using the following command:<\/p>\n<pre>ssh root@your_server_ip_address<\/pre>\n<p>After successfully logging in, we will create a new user called <em>donald<\/em> and grant him administrative privileges. You can name your user whatever you want.<\/p>\n<pre>useradd --create-home --shell \"\/bin\/bash\" --groups sudo donald<\/pre>\n<p>Create a hidden folder to your user account home directory on your cloud server with the following command:<\/p>\n<pre>mkdir -p \/home\/donald\/.ssh<\/pre>\n<p>Insert public key from your key pair on your local machine to <em>authorized_keys<\/em> in the previously created hidden folder.<\/p>\n<pre>echo \"your_public_key\" &gt;&gt; \/home\/donald\/.ssh\/authorized_keys<\/pre>\n<p>Adjust SSH configuration ownership and permissions:<\/p>\n<pre>chmod 0700 \/home\/donald\/.ssh\nchmod 0600 \/home\/donald\/.ssh\/authorized_keys\nchown -R donald:donald \/home\/donald\/.ssh<\/pre>\n<p>Disable root to log in using SSH:<\/p>\n<pre>sed -i 's\/^PermitRootLogin.*\/PermitRootLogin no\/g' \/etc\/ssh\/sshd_config<\/pre>\n<p>Disable login with password:<\/p>\n<pre>sed -i 's\/^PasswordAuthentication.*\/PasswordAuthentication no\/g' \/etc\/ssh\/sshd_config<\/pre>\n<p>Restart the SSH service to apply the changes by using the command below:<\/p>\n<pre>systemctl restart sshd<\/pre>\n<p>You can configure the firewall using <a href=\"https:\/\/upcloud.com\/global\/docs\/guides\/managing-firewall\/\" target=\"_blank\" rel=\"noopener\">UpCloud Firewall<\/a>. But, in this tutorial, we will set up a basic firewall by using UFW application. By doing this we will make sure to allow connections only to certain services. First, you need to install UFW with the next command:<\/p>\n<pre>apt install ufw<\/pre>\n<p>Sometimes, the application can already have registered profiles for UFW, so it can be managed with those profile names. You can check which applications have these profiles by inserting the following command:<\/p>\n<pre>ufw app list<\/pre>\n<p>You should at least get an OpenSSH as an answer since we are going to allow it in our firewall with:<\/p>\n<pre>ufw allow OpenSSH<\/pre>\n<p>Now we just need to enable ufw with the next command:<\/p>\n<pre>ufw enable<\/pre>\n<p>All other connections, that we explicitly did not set in allow list, are blocked. You can check the current status of your firewall at any time by typing:<\/p>\n<pre>ufw status<\/pre>\n<p>At this point, you have a solid foundation for your server. You should log out from your root user and login with your private key to your newly created user.<\/p>\n<h4>For consideration<\/h4>\n<p>Make sure to regularly check for updates on your server. Begin by updating the package list:<\/p>\n<pre>apt update<\/pre>\n<p>Next, upgrade installed packages to their latest available versions:<\/p>\n<pre>apt upgrade<\/pre>\n<p>Once the updates have finished, you can perform additional upgrades that involve changing dependencies, adding or removing new packages as necessary, with the following command:<\/p>\n<pre>apt dist-upgrade<\/pre>\n<p>This will take care of a set of upgrades which may have been held back by regular upgrade command.<\/p>\n<h2>Step 3 &#8211; Setup Certbot to acquire Let&#8217;s Encrypt TLS Certificate<\/h2>\n<p><a href=\"https:\/\/letsencrypt.org\/\" target=\"_blank\" rel=\"noopener\">Let\u2019s Encrypt<\/a> is a nonprofit Certificate Authority providing free TLS certificate for your site. In this section, you will learn how to set up <a href=\"https:\/\/certbot.eff.org\/\" target=\"_blank\" rel=\"noopener\">Certbot<\/a> to automatically acquire SSL certificates. You need to install Certbot, but to be sure that you get the latest version, first, add Certbot\u2019s repository:<\/p>\n<pre>sudo add-apt-repository ppa:certbot\/certbot<\/pre>\n<p>Next, you need to update the package list with the newest repository:<\/p>\n<pre>sudo apt update<\/pre>\n<p>Install Certbot with the following command:<\/p>\n<pre>sudo apt install certbot<\/pre>\n<p>Certbot needs an open port 80 or 443 to acquire the TLS certificate, and since we are blocking all ports (except SSH) with firewall, you need to open one of these two. We are going to use port 80:<\/p>\n<pre>sudo ufw allow 80<\/pre>\n<p>Now, we can run our Certbot. Use the next command and follow onscreen instruction:<\/p>\n<pre>sudo certbot certonly --standalone --preferred-challenges http -d mqtt.example.com<\/pre>\n<p>You\u2019ll need to complete the following selection:<\/p>\n<ol>\n<li>On the first installation on any specific host, you will need to enter a contact email.<\/li>\n<li>Next, go through the Let\u2019s Encrypt Terms of Service and select Agree if you accept the terms and wish to use the service.<\/li>\n<li>Lastly, select whether you want to share your email address with the Electronic Frontier Foundation, a founding partner of the Let\u2019s Encrypt project and the non-profit organization that develops Certbot.<\/li>\n<\/ol>\n<p>That is it! You should see the congratulation message and also a path where your certificates are stored. Please remember this path because you will need for subsequent actions. Anyhow, it should be in <em>\/etc\/letsencrypt\/live\/mqtt.example.com<\/em> folder (replace <span style=\"color: #ff0000;\">mqtt.example.com<\/span> with your domain). You can list your certificates with:<\/p>\n<pre>sudo ls \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span><\/pre>\n<p>This certificate is only valid for 90 days, but Certbot adds a script to cron.d that runs twice a day and automatically renews any certificate that is within 30 days of expiration. Later on, we are going to cover renewals and adding some extra commands to renew config file.<\/p>\n<h2>Step 4 &#8211; Install and configure Mosquitto MQTT broker<\/h2>\n<p><a href=\"https:\/\/mosquitto.org\/\" target=\"_blank\" rel=\"noopener\">Eclipse Mosquitto<\/a> is an open-source (EPL\/EDL licensed) message broker that implements the MQTT protocol versions 5.0, 3.1.1 and 3.1. Mosquitto is lightweight and is suitable for use on all devices from low power single board computers to full servers. To install the latest version of Mosquitto you will firstly need to add Mosquitto\u2019s repository:<\/p>\n<pre>sudo apt-add-repository ppa:mosquitto-dev\/mosquitto-ppa<\/pre>\n<p>Next, you need to update the packages list with the newest repository:<\/p>\n<pre>sudo apt update<\/pre>\n<p>Then, install Mosquitto with the following command:<\/p>\n<pre>sudo apt install mosquitto mosquitto-clients<\/pre>\n<p>By doing this, you have successfully installed Mosquitto MQTT broker. You can use it out-of-the-box as installed, but we do not recommend that. We suggest you configure your server for some additional security. We will add a new Mosquitto user secured with a password using the following command:<\/p>\n<pre>sudo mosquitto_passwd -c \/etc\/mosquitto\/passwd mqttdonald<\/pre>\n<p>Open up a new configuration file named <em>custom.conf<\/em> in <em>\/etc\/mosquitto\/conf.d\/<\/em> folder:<\/p>\n<pre>sudo vi \/etc\/mosquitto\/conf.d\/custom.conf<\/pre>\n<p>Copy the following commands and paste them in the <em>custom.conf<\/em> file. Replace the <span style=\"color: #ff0000;\"><em>mqtt.example.com<\/em><\/span> with your domain on each certificate and key file line.<\/p>\n<pre>allow_anonymous false\npassword_file \/etc\/mosquitto\/passwd\nlistener 1883 localhost\nlistener 8883\ncertfile \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span>\/cert.pem\ncafile \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span>\/chain.pem\nkeyfile \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span>\/privkey.pem\nlistener 8083\nprotocol websockets\ncertfile \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span>\/cert.pem\ncafile \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span>\/chain.pem\nkeyfile \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span>\/privkey.pem<\/pre>\n<p>Save the file and exit by typing the <em>:wq<\/em> command.<\/p>\n<p>Also, make sure Mosquitto service will have access to the certificate files.<\/p>\n<pre>sudo setfacl -R -m u:mosquitto:rX \/etc\/letsencrypt\/{live,archive}<\/pre>\n<p>Next, the Mosquitto broker needs to be restarted so the configuration can take place.<\/p>\n<pre>sudo systemctl restart mosquitto<\/pre>\n<p>After this, add new rules to firewall to match the <em>.conf<\/em> file:<\/p>\n<pre>sudo ufw allow 8883<\/pre>\n<pre>sudo ufw allow 8083<\/pre>\n<p>With this configuration file, we told our MQTT broker that anonymous users will not be tolerated. We have specified the path to a file where passwords are being stored. We have configured three listeners. First is on port 1883 which is unencrypted and only allowed to be used in the localhost environment. It is mostly intended for testing purposes. The second listener is on port 8883, which is encrypted with TLS certificate. The third listener is on port 8083 which is encrypted with TLS certificate as well, but it is intended for use over WebSocket protocol.<\/p>\n<p>For the testing purposes, log in to your server in a second terminal to have two command line available at the same time.<\/p>\n<p>In the first terminal, run the following command to subscribe to some topics (e.g. \u201cmqtt_topic_name\u201d):<\/p>\n<pre>mosquitto_sub -h localhost -t mqtt_topic_name -u \"mqttdonald\" -P \"password\"<\/pre>\n<p>Then, in the second terminal, run the following command to publish the message to the previously mentioned topic:<\/p>\n<pre>mosquitto_pub -h mqtt.example.com -t mqtt_topic_name -m \"Hello MQTT World\" -p 8883 --capath \/etc\/ssl\/certs\/ -u \"mqttdonald\" -P \"password\"<\/pre>\n<p>You should receive the following message: \u201cHello MQTT World\u201d in the first terminal.<\/p>\n<p>Do not forget to close the second terminal and exit from mosquitto_sub command in the first terminal with CTRL+C.<\/p>\n<p>To test your MQTT broker via WebSocket you can use some popular online services like <a href=\"https:\/\/www.eclipse.org\/paho\/clients\/js\/utility\/\" target=\"_blank\" rel=\"noopener\">Eclipse Paho<\/a>, <a href=\"http:\/\/www.hivemq.com\/demos\/websocket-client\/\" target=\"_blank\" rel=\"noopener\">HiveMQ<\/a>, <a href=\"https:\/\/chrome.google.com\/webstore\/detail\/mqttlens\/hemojaaeigabkbcookmlgmdigohjobjm\" target=\"_blank\" rel=\"noopener\">MQTTLens<\/a>, or some other that you prefer.<\/p>\n<h2>Step 5 &#8211; Install Node.js<\/h2>\n<p><a href=\"https:\/\/nodejs.org\/\" target=\"_blank\" rel=\"noopener\">Node.js<\/a> is an open-source, cross-platform, JavaScript runtime environment that executes JavaScript code outside of a web browser. Node.js lets developers use JavaScript to write command-line tools and for server-side scripting to produce dynamic web page content before the page is sent to the user\u2019s web browser.<\/p>\n<p>As with the other software we\u2019ve installed so far, we first need to add Node.js repository to get the latest version. But, this time procedure is somewhat different. We are going to add the repository by using the following command, which will execute a script from the URL:<\/p>\n<pre>curl -sL https:\/\/deb.nodesource.com\/setup_12.x | sudo -E bash -<\/pre>\n<p>Now we can install Node.js:<\/p>\n<pre>sudo apt install nodejs<\/pre>\n<p>To be sure that <em>npm<\/em> (which is installed with Node.js) is going to work properly you need to install additional packages that have some general usage like compilers, libraries and some other utilities:<\/p>\n<pre>sudo apt install build-essential<\/pre>\n<p>We are later going to cover the setup of a basic webpage with Node.js.<\/p>\n<h2>Step 6 &#8211; Install MongoDB<\/h2>\n<p><a href=\"https:\/\/www.mongodb.com\/\" target=\"_blank\" rel=\"noopener\">MongoDB<\/a> is a general-purpose, cross-platform document-based database program. Classified as a NoSQL database program, MongoDB uses JSON-like documents with schema and it is built for modern application developers and for the cloud era. To install the latest version you need to import the MongoDB public GPG Key from the URL below and manually add the repository:<\/p>\n<pre>wget -qO - https:\/\/www.mongodb.org\/static\/pgp\/server-4.2.asc | sudo apt-key add -<\/pre>\n<p>Create a list file for MongoDB on your version of Ubuntu:<\/p>\n<pre>echo \"deb [ arch=amd64,arm64 ] https:\/\/repo.mongodb.org\/apt\/ubuntu bionic\/mongodb-org\/4.2 multiverse\" | sudo tee \/etc\/apt\/sources.list.d\/mongodb-org-4.2.list<\/pre>\n<p>Update package list with the newest repository:<\/p>\n<pre>sudo apt update<\/pre>\n<p>Install the latest stable version:<\/p>\n<pre>sudo apt install mongodb-org<\/pre>\n<p>Next, we need to start the service manually with the following command:<\/p>\n<pre>sudo systemctl start mongod<\/pre>\n<p>Then, enable the MongoDB service to have it start at system boot:<\/p>\n<pre>sudo systemctl enable mongod<\/pre>\n<p>That is it! We are not going to expose mongo service outside from our server, so we can use MongoDB as it is \u2013 with the default configuration.<\/p>\n<h2>Step 7 &#8211; Setup Simple Website<\/h2>\n<p>In this step, we will show you how to set up a basic website. We will keep things simple and set up everything manually. First, we are going to create our main work folder:<\/p>\n<pre>mkdir ~\/webserver<\/pre>\n<p>Then we are going to navigate to our newly created folder:<\/p>\n<pre>cd ~\/webserver<\/pre>\n<p>Now we can install the required npm packages:<\/p>\n<pre>npm install express ejs mqtt socket.io moment jquery mongoose<\/pre>\n<p>In our Simple Website, we will have two pages \u2013 Main and History. Since we are using EJS template engine and will need one more additional folder for these files:<\/p>\n<pre>mkdir views<\/pre>\n<p>EJS is a simple templating language that lets you generate HTML pages. Our first page is for the Main view, where we are going to make real-time MQTT dataflow. Open a new file called main in the folder views:<\/p>\n<pre>vi views\/main.ejs<\/pre>\n<p>Copy the following EJS\/HTML code and paste it to your newly created file:<\/p>\n<pre>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;title&gt;MQTT Client - Mainpage&lt;\/title&gt;\n    &lt;script type=\"text\/javascript\" src=\"\/lib\/socket.io.js\"&gt;&lt;\/script&gt;\n    &lt;script type=\"text\/javascript\" src=\"\/lib\/jquery.min.js\"&gt;&lt;\/script&gt;\n    &lt;script type=\"text\/javascript\"&gt;\n      var socket = io();\n      socket.on('mqtt', function(msg) {\n      $('#tbl').prepend('&lt;tr&gt;&lt;td&gt;' + msg.datetime + '&lt;\/td&gt;&lt;td&gt;' + msg.topic + '&lt;\/td&gt;&lt;td&gt;' + msg.message + '&lt;\/td&gt;&lt;\/tr&gt;');\n      });\n    &lt;\/script&gt;\n    &lt;style&gt;\n      table, th, td {\n        border: 1px solid black;\n      }\n      table {\n        width: 100%;\n      }\n      .col1 {\n        min-width: 150px;\n        text-align: left;\n      }\n      .col2 {\n        width: 40%;\n        text-align: left;\n      }\n      .col3 {\n        width: 40%;\n        text-align: left;\n      }\n    &lt;\/style&gt;\n  &lt;\/head&gt;\n  &lt;body&gt;\n    &lt;div&gt;\n      &lt;a href=\"\/\"&gt;MAIN&lt;\/a&gt; &lt;a href=\"\/history\"&gt;HISTORY&lt;\/a&gt;\n    &lt;\/div&gt;\n    &lt;div&gt;\n      &lt;table&gt;\n        &lt;thead&gt;\n          &lt;tr&gt;\n            &lt;th class=\"col1\"&gt;Datetime&lt;\/th&gt;\n            &lt;th class=\"col2\"&gt;Topic&lt;\/th&gt;\n            &lt;th class=\"col3\"&gt;Payload&lt;\/th&gt;\n          &lt;\/tr&gt;\n        &lt;\/thead&gt;\n        &lt;tbody id=\"tbl\"&gt;&lt;\/tbody&gt;\n      &lt;\/table&gt;\n    &lt;\/div&gt;\n  &lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n<p>Then save the file and exit the editor.<\/p>\n<p>Next, again in the <em>views<\/em> folder, open new a file called <em>history.ejs<\/em>:<\/p>\n<pre>vi views\/history.ejs<\/pre>\n<p>Paste the following code, which will create a web page where the recorded data from the database will be shown:<\/p>\n<pre>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;title&gt;MQTT Client - History&lt;\/title&gt;\n    &lt;style&gt;\n      table, th, td {\n        border: 1px solid black;\n      }\n      table {\n        width: 100%;\n      }\n      .col1 {\n        min-width: 150px;\n        text-align: left;\n      }\n      .col2 {\n        width: 40%;\n        text-align: left;\n      }\n      .col3 {\n        width: 40%;\n        text-align: left;\n      }\n    &lt;\/style&gt;\n  &lt;\/head&gt;\n  &lt;body&gt;\n    &lt;div&gt;\n      &lt;a href=\"\/\"&gt;MAIN&lt;\/a&gt; &lt;a href=\"\/history\"&gt;HISTORY&lt;\/a&gt;\n    &lt;\/div&gt;\n    &lt;div&gt;\n      &lt;table&gt;\n        &lt;thead&gt;\n          &lt;tr&gt;\n            &lt;th class=\"col1\"&gt;Datetime&lt;\/th&gt;\n            &lt;th class=\"col2\"&gt;Topic&lt;\/th&gt;\n            &lt;th class=\"col3\"&gt;Payload&lt;\/th&gt;\n          &lt;\/tr&gt;\n        &lt;\/thead&gt;\n        &lt;tbody id=\"tbl\"&gt;\n          &lt;% history.forEach(function (data) { %&gt;\n          &lt;tr&gt;\n            &lt;td&gt;&lt;%= data.datetime %&gt;&lt;\/td&gt;\n            &lt;td&gt;&lt;%= data.topic %&gt;&lt;\/td&gt;\n            &lt;td&gt;&lt;%= data.payload %&gt;&lt;\/td&gt;\n          &lt;\/tr&gt;\n          &lt;% }) %&gt;\n        &lt;\/tbody&gt;\n      &lt;\/table&gt;\n    &lt;\/div&gt;\n  &lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n<p>Lastly, we have the most important file where the main JavaScript code for our Node.js web server is going to go. Open a new file called server.js in the main work folder:<\/p>\n<pre>vi ~\/webserver\/server.js<\/pre>\n<p>With this code, we are implementing MQTT client and storing received data in the MongoDB database. Paste the following code.<\/p>\n<p>Remember to replace the relevant parts with your own data including your <span style=\"color: #ff0000;\">domain name<\/span> and MQTT <span style=\"color: #ff0000;\">username<\/span> and <span style=\"color: #ff0000;\">password<\/span>.<\/p>\n<pre>#!\/usr\/bin\/env node\n\n\/** server.js *\/\n\n\/\/ Dependencies\nconst fs = require('fs');\nconst http = require('http');\nconst https = require('https');\nconst express = require('express');\nconst path = require('path');\nconst mqtt = require('mqtt');\nconst moment = require('moment');\nconst mongoose = require(\"mongoose\");\n\n\/\/Certificate\nconst privateKey = fs.readFileSync('\/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span>\/privkey.pem', 'utf8');\nconst certificate = fs.readFileSync('\/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span>\/cert.pem', 'utf8');\nconst ca = fs.readFileSync('\/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span>\/chain.pem', 'utf8');\n\nconst credentials = {\n  key: privateKey,\n  cert: certificate,\n  ca: ca\n};\n\n\/\/Connection to MongoDB\nmongoose.Promise = global.Promise;\nmongoose.connect(\"mongodb:\/\/localhost:27017\/mqtt\", { useNewUrlParser: true, useUnifiedTopology: true } );\n\n\/\/MongoDB MQTT Schema\nvar mqttSchema = new mongoose.Schema({\n  datetime: {\n    type: String,\n    default: () =&gt; moment().format(\"YYYY-MM-DD HH:mm:ss\")\n  },\n  topic: String,\n  payload: String\n});\nvar MqttData = mongoose.model(\"mqttData\", mqttSchema);\n\n\/\/Connection to MQTT\nconst client = mqtt.connect('mqtts:\/\/mqtt.example.com', {\n  port: 8883,\n  username: '<span style=\"color: #ff0000;\">mqttdonald<\/span>',\n  password: '<span style=\"color: #ff0000;\">##########<\/span>'\n});\n\n\/\/Creating Express App\nconst app = express();\n\n\/\/Starting both http &amp; https servers\nconst httpServer = http.createServer(app);\nconst httpsServer = https.createServer(credentials, app);\n\n\/\/Connection to Socket.io\nconst io = require('socket.io')(httpsServer);\n\n\/\/Handling new user\nio.on('connection', function(socket){\n  console.log('A new user has been connected');\n});\n\n\/\/Subscribing to # topic on connection\nclient.on('connect', function () {\n  client.subscribe('#', function (err) {});\n});\n\n\/\/On received MQTT message\nclient.on('message', function (topic, message) {\n  \/\/Emit event to socket\n  io.emit(\"mqtt\", { datetime: moment().format(\"YYYY-MM-DD HH:mm:ss\"), topic: topic, message: message.toString()});\n\n  \/\/Saving received data to MongoDB\n  var mongomqttdata = new MqttData({\n    topic: topic,\n    payload: message.toString()\n  });\n  mongomqttdata.save();\n});\n\n\/\/Use EJS view engine\napp.set('view engine', 'ejs');\n\n\/\/Expose socket.io-client and jquery to clients in browser\napp.use('\/lib', express.static(path.join(__dirname, 'node_modules\/socket.io-client\/dist\/')));\napp.use('\/lib', express.static(path.join(__dirname, 'node_modules\/jquery\/dist')));\n\n\/\/If request is via https execute next, else redirect to https\napp.use((req, res, next) =&gt; {\n  if (req.secure) {\n    next();\n  } else {\n    res.redirect('https:\/\/' + req.headers.host + req.url);\n  }\n});\n\n\/\/Render History page\napp.use('\/history', (req, res) =&gt; {\n  MqttData.find({}, function(err, data) {\n    res.render('history', {\n      history: data\n    });\n  });\n});\n\n\/\/Render Main page\napp.use('\/', (req, res) =&gt; {\n  res.render('main');\n});\n\n\/\/Open https listener\nhttpsServer.listen(443, () =&gt; {\n  console.log('HTTPS Server running on port 443');\n});\n\n\/\/Open http listener\nhttpServer.listen(80, () =&gt; {\n  console.log('HTTP Server running on port 80');\n});<\/pre>\n<p>Afterwards, save the file and exit the editor.<\/p>\n<p>We are then done with the coding of our webpage, now we just need to open port 443 in the firewall (port 80 is already opened):<\/p>\n<pre>sudo ufw allow 443<\/pre>\n<p>You can now test your node application with:<\/p>\n<pre>sudo node server.js<\/pre>\n<p>Open your domain on a web browser, publish something to your MQTT broker and that message should appear on the web page. Open history page and you should be able to see previously input messages.<\/p>\n<p>However, our job is still not finished with the web page since we need to make it start and run with the system.<\/p>\n<p>First, we will make our server.js file executable:<\/p>\n<pre>sudo chmod +x ~\/webserver\/server.js<\/pre>\n<p>Then, we need to create a new file that will actually be a service file in our system folder:<\/p>\n<pre>sudo vi \/etc\/systemd\/system\/webpage.service<\/pre>\n<p>Copy and paste the following code in your file:<\/p>\n<pre>[Unit]\nDescription=Node.js HTTPS Server\n\n[Service]\nPIDFile=\/tmp\/webpage-99.pid\nUser=root\nGroup=root\nRestart=always\nKillSignal=SIGQUIT\nWorkingDirectory=\/home\/donald\/webserver\/\nExecStart=\/home\/donald\/webserver\/server.js\n\n[Install]\nWantedBy=multi-user.target<\/pre>\n<p>To ensure that our <em>server.js<\/em> file is working properly as a service, make sure that you are using Unix-style newlines.<\/p>\n<p>This can be done by opening the <em>server.js<\/em> file using the <em>vi<\/em> text editor:<\/p>\n<pre>sudo vi server.js<\/pre>\n<p>Edit and save the file with the following commands:<\/p>\n<pre>:se ff=unix\n:wq<\/pre>\n<p>Then, enable the service and start it<\/p>\n<pre>sudo systemctl enable webpage.service\nsudo systemctl start webpage.service<\/pre>\n<p>To check that everything is working properly you can run:<\/p>\n<pre>sudo systemctl status webpage.service<\/pre>\n<p>That is it! You are now done with your web page.<\/p>\n<h2>Step 8 &#8211; Adding renew hooks to Certbot<\/h2>\n<p>All that is left now is to fix our automatic SSL renew hook. Since the port 80 is already occupied with Node.js server we need to temporarily open it. After successful certificate renewal, we need to restart involved services, Mosquitto and the webpage. Open the Certbot renew hook configuration file. Note that you need to open the configuration file specific to <span style=\"color: #ff0000;\">your domain name<\/span>.<\/p>\n<pre>sudo vi \/etc\/letsencrypt\/renewal\/<span style=\"color: #ff0000;\">mqtt.example.com<\/span>.conf<\/pre>\n<p>Next, append the following commands to the end of the file:<\/p>\n<pre>renew_hook = systemctl restart mosquitto.service ; systemctl restart webpage.service\npost_hook = systemctl start webpage.service\npre_hook = systemctl stop webpage.service<\/pre>\n<p>Then save your file and run following command to test your new renew conf file:<\/p>\n<pre>sudo certbot renew --dry-run<\/pre>\n<p>Certbot will then make a dry-run to attempt to renew the SSL certificates without actually making any changes.<\/p>\n<p>Once finished, if there are no errors, you\u2019ve succeeded and everything is set!<\/p>\n<h2>Conclusion<\/h2>\n<p>We hope that this tutorial helped you learn about the MQTT broker and additional applications that expand its capabilities and make it more secure. We kept things simple, and it is up to you to adapt it for some real usage. Feel free to post a comment with your impressions or suggestions. Thank you for your attention!<\/p>\n","protected":false},"author":41,"featured_media":15430,"comment_status":"open","ping_status":"closed","template":"","community-category":[223,259],"class_list":["post-2161","tutorial","type-tutorial","status-publish","has-post-thumbnail","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/2161","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial"}],"about":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/types\/tutorial"}],"author":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/comments?post=2161"}],"version-history":[{"count":2,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/2161\/revisions"}],"predecessor-version":[{"id":3446,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/2161\/revisions\/3446"}],"wp:attachment":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/media?parent=2161"}],"wp:term":[{"taxonomy":"community-category","embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/community-category?post=2161"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}