Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the acf domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php on line 6131

Deprecated: Creation of dynamic property ACF::$fields is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/fields.php on line 138

Deprecated: Creation of dynamic property acf_loop::$loops is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/loop.php on line 28

Deprecated: Creation of dynamic property ACF::$loop is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/loop.php on line 269

Deprecated: Creation of dynamic property ACF::$revisions is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/revisions.php on line 397

Deprecated: Creation of dynamic property acf_validation::$errors is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/validation.php on line 28

Deprecated: Creation of dynamic property ACF::$validation is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/validation.php on line 214

Deprecated: Creation of dynamic property acf_form_customizer::$preview_values is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-customizer.php on line 28

Deprecated: Creation of dynamic property acf_form_customizer::$preview_fields is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-customizer.php on line 29

Deprecated: Creation of dynamic property acf_form_customizer::$preview_errors is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-customizer.php on line 30

Deprecated: Creation of dynamic property ACF::$form_front is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-front.php on line 598

Deprecated: Creation of dynamic property acf_form_widget::$preview_values is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-widget.php on line 34

Deprecated: Creation of dynamic property acf_form_widget::$preview_reference is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-widget.php on line 35

Deprecated: Creation of dynamic property acf_form_widget::$preview_errors is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-widget.php on line 36

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the all-in-one-wp-migration domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php on line 6131

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/wp_plugin/wp_plugin.php on line 23

Deprecated: str_replace(): Passing null to parameter #3 ($subject) of type array|string is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/wp-super-cache/wp-cache-phase2.php on line 54

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/wp-super-cache/wp-cache-phase2.php on line 1539

Deprecated: strtolower(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/wp-super-cache/wp-cache-phase2.php on line 828

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the rocket domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php on line 6131

Deprecated: Creation of dynamic property acf_field_oembed::$width is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/fields/class-acf-field-oembed.php on line 31

Deprecated: Creation of dynamic property acf_field_oembed::$height is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/fields/class-acf-field-oembed.php on line 32

Deprecated: Creation of dynamic property acf_field_google_map::$default_values is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/fields/class-acf-field-google-map.php on line 33

Deprecated: Creation of dynamic property acf_field__group::$have_rows is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/fields/class-acf-field-group.php on line 31

Deprecated: Creation of dynamic property acf_field_clone::$cloning is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/pro/fields/class-acf-field-clone.php on line 34

Deprecated: Creation of dynamic property acf_field_clone::$have_rows is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/pro/fields/class-acf-field-clone.php on line 35

Deprecated: Creation of dynamic property jh_acf_field_table::$settings is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-table-field/class-jh-acf-field-table.php on line 23

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902
{"id":24897,"date":"2020-06-12T07:49:28","date_gmt":"2020-06-12T04:49:28","guid":{"rendered":"https:\/\/upcloud.com\/community\/tutorials\/install-secure-mqtt-broker-ubuntu"},"modified":"2020-06-12T07:49:28","modified_gmt":"2020-06-12T04:49:28","slug":"install-secure-mqtt-broker-ubuntu","status":"publish","type":"tutorial","link":"https:\/\/studiogo.tech\/upcloudold\/tutorial\/install-secure-mqtt-broker-ubuntu\/","title":{"rendered":"How to install secure MQTT broker on Ubuntu"},"content":{"rendered":"

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

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’s 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

Test hosting on UpCloud!<\/a><\/p>\n<\/p>\n

Prerequisites<\/h2>\n

Domain name<\/h4>\n

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. Namecheap<\/a>, GoDaddy<\/a>, 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 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 mqtt.example.com<\/span> domain name as an example, replace it with your domain where asked.<\/p>\n

Key pair<\/h4>\n

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

On Linux and macOS open a terminal window. At the shell prompt, type the following command:<\/p>\n

ssh-keygen -t rsa<\/pre>\n

The 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

On Windows, download and install PuTTY from the official website<\/a>. Go to Start > All Programs > PuTTY > 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’s 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<\/p>\n

Step 1 – Deploying a Cloud Server<\/h2>\n

First things first, if you are not registered on the UpCloud yet, begin by getting signed up<\/a>. Take a moment to create an account after which you can easily deploy your own cloud servers<\/a>.<\/p>\n

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 how to deploy a server<\/a>.<\/p>\n<\/p>\n

Step 2 – Initial Server Configuration<\/h2>\n

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 Initialization Scripts<\/a>, or manually after the deployment phase, you should skip this step.<\/p>\n

If you are not already connected to your server, go ahead and log in as the root user using the following command:<\/p>\n

ssh root@your_server_ip_address<\/pre>\n

After successfully logging in, we will create a new user called donald<\/em> and grant him administrative privileges. You can name your user whatever you want.<\/p>\n

useradd --create-home --shell \"\/bin\/bash\" --groups sudo donald<\/pre>\n

Create a hidden folder to your user account home directory on your cloud server with the following command:<\/p>\n

mkdir -p \/home\/donald\/.ssh<\/pre>\n

Insert public key from your key pair on your local machine to authorized_keys<\/em> in the previously created hidden folder.<\/p>\n

echo \"your_public_key\" >> \/home\/donald\/.ssh\/authorized_keys<\/pre>\n

Adjust SSH configuration ownership and permissions:<\/p>\n

chmod 0700 \/home\/donald\/.ssh\nchmod 0600 \/home\/donald\/.ssh\/authorized_keys\nchown -R donald:donald \/home\/donald\/.ssh<\/pre>\n

Disable root to log in using SSH:<\/p>\n

sed -i 's\/^PermitRootLogin.*\/PermitRootLogin no\/g' \/etc\/ssh\/sshd_config<\/pre>\n

Disable login with password:<\/p>\n

sed -i 's\/^PasswordAuthentication.*\/PasswordAuthentication no\/g' \/etc\/ssh\/sshd_config<\/pre>\n

Restart the SSH service to apply the changes by using the command below:<\/p>\n

systemctl restart sshd<\/pre>\n

You can configure the firewall using 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

apt install ufw<\/pre>\n

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

ufw app list<\/pre>\n

You should at least get an OpenSSH as an answer since we are going to allow it in our firewall with:<\/p>\n

ufw allow OpenSSH<\/pre>\n

Now we just need to enable ufw with the next command:<\/p>\n

ufw enable<\/pre>\n

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

ufw status<\/pre>\n

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

For consideration<\/h4>\n

Make sure to regularly check for updates on your server. Begin by updating the package list:<\/p>\n

apt update<\/pre>\n

Next, upgrade installed packages to their latest available versions:<\/p>\n

apt upgrade<\/pre>\n

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

apt dist-upgrade<\/pre>\n

This will take care of a set of upgrades which may have been held back by regular upgrade command.<\/p>\n<\/p>\n

Step 3 – Setup Certbot to acquire Let’s Encrypt TLS Certificate<\/h2>\n

Let’s Encrypt<\/a> is a nonprofit Certificate Authority providing free TLS certificate for your site. In this section, you will learn how to set up 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’s repository:<\/p>\n

sudo add-apt-repository ppa:certbot\/certbot<\/pre>\n

Next, you need to update the package list with the newest repository:<\/p>\n

sudo apt update<\/pre>\n

Install Certbot with the following command:<\/p>\n

sudo apt install certbot<\/pre>\n

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

sudo ufw allow 80<\/pre>\n

Now, we can run our Certbot. Use the next command and follow onscreen instruction:<\/p>\n

sudo certbot certonly --standalone --preferred-challenges http -d mqtt.example.com<\/pre>\n

You’ll need to complete the following selection:<\/p>\n

    \n
  1. On the first installation on any specific host, you will need to enter a contact email.<\/li>\n
  2. 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
  3. 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

    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 \/etc\/letsencrypt\/live\/mqtt.example.com<\/em> folder (replace mqtt.example.com<\/span> with your domain). You can list your certificates with:<\/p>\n

    sudo ls \/etc\/letsencrypt\/live\/mqtt.example.com<\/span><\/pre>\n

    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<\/p>\n

    Step 4 – Install and configure Mosquitto MQTT broker<\/h2>\n

    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’s repository:<\/p>\n

    sudo apt-add-repository ppa:mosquitto-dev\/mosquitto-ppa<\/pre>\n

    Next, you need to update the packages list with the newest repository:<\/p>\n

    sudo apt update<\/pre>\n

    Then, install Mosquitto with the following command:<\/p>\n

    sudo apt install mosquitto mosquitto-clients<\/pre>\n

    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

    sudo mosquitto_passwd -c \/etc\/mosquitto\/passwd mqttdonald<\/pre>\n

    Open up a new configuration file named custom.conf<\/em> in \/etc\/mosquitto\/conf.d\/<\/em> folder:<\/p>\n

    sudo vi \/etc\/mosquitto\/conf.d\/custom.conf<\/pre>\n

    Copy the following commands and paste them in the custom.conf<\/em> file. Replace the mqtt.example.com<\/em><\/span> with your domain on each certificate and key file line.<\/p>\n

    allow_anonymous false\npassword_file \/etc\/mosquitto\/passwd\nlistener 1883 localhost\nlistener 8883\ncertfile \/etc\/letsencrypt\/live\/mqtt.example.com<\/span>\/cert.pem\ncafile \/etc\/letsencrypt\/live\/mqtt.example.com<\/span>\/chain.pem\nkeyfile \/etc\/letsencrypt\/live\/mqtt.example.com<\/span>\/privkey.pem\nlistener 8083\nprotocol websockets\ncertfile \/etc\/letsencrypt\/live\/mqtt.example.com<\/span>\/cert.pem\ncafile \/etc\/letsencrypt\/live\/mqtt.example.com<\/span>\/chain.pem\nkeyfile \/etc\/letsencrypt\/live\/mqtt.example.com<\/span>\/privkey.pem<\/pre>\n

    Save the file and exit by typing the :wq<\/em> command.<\/p>\n

    Also, make sure Mosquitto service will have access to the certificate files.<\/p>\n

    sudo setfacl -R -m u:mosquitto:rX \/etc\/letsencrypt\/{live,archive}<\/pre>\n

    Next, the Mosquitto broker needs to be restarted so the configuration can take place.<\/p>\n

    sudo systemctl restart mosquitto<\/pre>\n

    After this, add new rules to firewall to match the .conf<\/em> file:<\/p>\n

    sudo ufw allow 8883<\/pre>\n
    sudo ufw allow 8083<\/pre>\n

    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

    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

    In the first terminal, run the following command to subscribe to some topics (e.g. “mqtt_topic_name”):<\/p>\n

    mosquitto_sub -h localhost -t mqtt_topic_name -u \"mqttdonald\" -P \"password\"<\/pre>\n

    Then, in the second terminal, run the following command to publish the message to the previously mentioned topic:<\/p>\n

    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

    You should receive the following message: “Hello MQTT World” in the first terminal.<\/p>\n

    Do not forget to close the second terminal and exit from mosquitto_sub command in the first terminal with CTRL+C.<\/p>\n

    To test your MQTT broker via WebSocket you can use some popular online services like Eclipse Paho<\/a>, HiveMQ<\/a>, MQTTLens<\/a>, or some other that you prefer.<\/p>\n<\/p>\n

    Step 5 – Install Node.js<\/h2>\n

    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’s web browser.<\/p>\n

    As with the other software we’ve 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

    curl -sL https:\/\/deb.nodesource.com\/setup_12.x | sudo -E bash -<\/pre>\n

    Now we can install Node.js:<\/p>\n

    sudo apt install nodejs<\/pre>\n

    To be sure that 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

    sudo apt install build-essential<\/pre>\n

    We are later going to cover the setup of a basic webpage with Node.js.<\/p>\n<\/p>\n

    Step 6 – Install MongoDB<\/h2>\n

    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

    wget -qO - https:\/\/www.mongodb.org\/static\/pgp\/server-4.2.asc | sudo apt-key add -<\/pre>\n

    Create a list file for MongoDB on your version of Ubuntu:<\/p>\n

    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

    Update package list with the newest repository:<\/p>\n

    sudo apt update<\/pre>\n

    Install the latest stable version:<\/p>\n

    sudo apt install mongodb-org<\/pre>\n

    Next, we need to start the service manually with the following command:<\/p>\n

    sudo systemctl start mongod<\/pre>\n

    Then, enable the MongoDB service to have it start at system boot:<\/p>\n

    sudo systemctl enable mongod<\/pre>\n

    That is it! We are not going to expose mongo service outside from our server, so we can use MongoDB as it is – with the default configuration.<\/p>\n<\/p>\n

    Step 7 – Setup Simple Website<\/h2>\n

    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

    mkdir ~\/webserver<\/pre>\n

    Then we are going to navigate to our newly created folder:<\/p>\n

    cd ~\/webserver<\/pre>\n

    Now we can install the required npm packages:<\/p>\n

    npm install express ejs mqtt socket.io moment jquery mongoose<\/pre>\n

    In our Simple Website, we will have two pages – Main and History. Since we are using EJS template engine and will need one more additional folder for these files:<\/p>\n

    mkdir views<\/pre>\n

    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

    vi views\/main.ejs<\/pre>\n

    Copy the following EJS\/HTML code and paste it to your newly created file:<\/p>\n

    <!DOCTYPE html>\n<html>\n  <head>\n    <title>MQTT Client - Mainpage<\/title>\n    <script type=\"text\/javascript\" src=\"\/lib\/socket.io.js\"><\/script>\n    <script type=\"text\/javascript\" src=\"\/lib\/jquery.min.js\"><\/script>\n    <script type=\"text\/javascript\">\n      var socket = io();\n      socket.on('mqtt', function(msg) {\n      $('#tbl').prepend('<tr><td>' + msg.datetime + '<\/td><td>' + msg.topic + '<\/td><td>' + msg.message + '<\/td><\/tr>');\n      });\n    <\/script>\n    <style>\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    <\/style>\n  <\/head>\n  <body>\n    <div>\n      <a href=\"\/\">MAIN<\/a> <a href=\"\/history\">HISTORY<\/a>\n    <\/div>\n    <div>\n      <table>\n        <thead>\n          <tr>\n            <th class=\"col1\">Datetime<\/th>\n            <th class=\"col2\">Topic<\/th>\n            <th class=\"col3\">Payload<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody id=\"tbl\"><\/tbody>\n      <\/table>\n    <\/div>\n  <\/body>\n<\/html><\/pre>\n

    Then save the file and exit the editor.<\/p>\n

    Next, again in the views<\/em> folder, open new a file called history.ejs<\/em>:<\/p>\n

    vi views\/history.ejs<\/pre>\n

    Paste the following code, which will create a web page where the recorded data from the database will be shown:<\/p>\n

    <!DOCTYPE html>\n<html>\n  <head>\n    <title>MQTT Client - History<\/title>\n    <style>\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    <\/style>\n  <\/head>\n  <body>\n    <div>\n      <a href=\"\/\">MAIN<\/a> <a href=\"\/history\">HISTORY<\/a>\n    <\/div>\n    <div>\n      <table>\n        <thead>\n          <tr>\n            <th class=\"col1\">Datetime<\/th>\n            <th class=\"col2\">Topic<\/th>\n            <th class=\"col3\">Payload<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody id=\"tbl\">\n          <% history.forEach(function (data) { %>\n          <tr>\n            <td><%= data.datetime %><\/td>\n            <td><%= data.topic %><\/td>\n            <td><%= data.payload %><\/td>\n          <\/tr>\n          <% }) %>\n        <\/tbody>\n      <\/table>\n    <\/div>\n  <\/body>\n<\/html><\/pre>\n

    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

    vi ~\/webserver\/server.js<\/pre>\n

    With this code, we are implementing MQTT client and storing received data in the MongoDB database. Paste the following code.<\/p>\n

    Remember to replace the relevant parts with your own data including your domain name<\/span> and MQTT username<\/span> and password<\/span>.<\/p>\n

    #!\/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\/mqtt.example.com<\/span>\/privkey.pem', 'utf8');\nconst certificate = fs.readFileSync('\/etc\/letsencrypt\/live\/mqtt.example.com<\/span>\/cert.pem', 'utf8');\nconst ca = fs.readFileSync('\/etc\/letsencrypt\/live\/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: () => 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: 'mqttdonald<\/span>',\n  password: '##########<\/span>'\n});\n\n\/\/Creating Express App\nconst app = express();\n\n\/\/Starting both http & 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) => {\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) => {\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) => {\n  res.render('main');\n});\n\n\/\/Open https listener\nhttpsServer.listen(443, () => {\n  console.log('HTTPS Server running on port 443');\n});\n\n\/\/Open http listener\nhttpServer.listen(80, () => {\n  console.log('HTTP Server running on port 80');\n});<\/pre>\n

    Afterwards, save the file and exit the editor.<\/p>\n

    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

    sudo ufw allow 443<\/pre>\n

    You can now test your node application with:<\/p>\n

    sudo node server.js<\/pre>\n

    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

    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

    First, we will make our server.js file executable:<\/p>\n

    sudo chmod +x ~\/webserver\/server.js<\/pre>\n

    Then, we need to create a new file that will actually be a service file in our system folder:<\/p>\n

    sudo vi \/etc\/systemd\/system\/webpage.service<\/pre>\n

    Copy and paste the following code in your file:<\/p>\n

    [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

    To ensure that our server.js<\/em> file is working properly as a service, make sure that you are using Unix-style newlines.<\/p>\n

    This can be done by opening the server.js<\/em> file using the vi<\/em> text editor:<\/p>\n

    sudo vi server.js<\/pre>\n

    Edit and save the file with the following commands:<\/p>\n

    :se ff=unix\n:wq<\/pre>\n

    Then, enable the service and start it<\/p>\n

    sudo systemctl enable webpage.service\nsudo systemctl start webpage.service<\/pre>\n

    To check that everything is working properly you can run:<\/p>\n

    sudo systemctl status webpage.service<\/pre>\n

    That is it! You are now done with your web page.<\/p>\n<\/p>\n

    Step 8 – Adding renew hooks to Certbot<\/h2>\n

    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 your domain name<\/span>.<\/p>\n

    sudo vi \/etc\/letsencrypt\/renewal\/mqtt.example.com<\/span>.conf<\/pre>\n

    Next, append the following commands to the end of the file:<\/p>\n

    renew_hook = systemctl restart mosquitto.service ; systemctl restart webpage.service\npost_hook = systemctl start webpage.service\npre_hook = systemctl stop webpage.service<\/pre>\n

    Then save your file and run following command to test your new renew conf file:<\/p>\n

    sudo certbot renew --dry-run<\/pre>\n

    Certbot will then make a dry-run to attempt to renew the SSL certificates without actually making any changes.<\/p>\n

    Once finished, if there are no errors, you’ve succeeded and everything is set!<\/p>\n<\/p>\n

    Conclusion<\/h2>\n

    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><\/p>\n","protected":false},"featured_media":15430,"comment_status":"open","ping_status":"closed","template":"","community-category":[111,113],"class_list":["post-24897","tutorial","type-tutorial","status-publish","has-post-thumbnail","hentry","community-category-networking","community-category-integrations"],"acf":[],"_links":{"self":[{"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/tutorial\/24897","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/tutorial"}],"about":[{"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/types\/tutorial"}],"replies":[{"embeddable":true,"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/comments?post=24897"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/media\/15430"}],"wp:attachment":[{"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/media?parent=24897"}],"wp:term":[{"taxonomy":"community-category","embeddable":true,"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/community-category?post=24897"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}