IoT Network Deep Dive

In my last article, I tried to give a gist of one of the many ways how a Secured IoT system could be deployed. In this article, I shall demonstrate another common way to secure your IoT Network by shielding it from the outer world.

I will also show, how web apps could interact with the MQTT broker which brings endless possibilities as raw sensor data could be accessed seamlessly in FrontEnd Apps.

The things I will be talking about are:

  • WebSocket protocol support for the Broker
  • Reverse Proxying the Broker

I will not be using something new, it’s the same Raspberry Pi IoT gateway, and a PC or Mac, that I have referred to in my previous articles.

NGINX as a reverse proxy for the MQTT Broker with WebSocket Support

MQTT is the most ideal IoT protocol for constrained devices as well as for unreliable networks. It’s the perfect way to send messages with very low network overhead. In the scenarios, where the devices need to communicate to the web apps on the cloud or mobile devices, MQTT natively cannot send and receive messages to the browser, e.g ChromeApp or on mobile phone.In that case, WebSocket protocol comes to the rescue. Wrapping up the MQTT protocol packets into the WebSocket packet enable the WebApps to leverage all MQTT features. The WebSocket protocol standardises the way the server can send content to the client without being first requested by the client, and allowing messages to be passed back and forth while keeping the connection open with very low overheads and in real-time. In this way, a two-way ongoing conversation can take place between the client and the server. The communications are done over TCP port number 80 (or 443 in the case of TLS-encrypted connections), which is of benefit for those environments which block non-web Internet connections using a firewall.

In the IoT scenario this encapsulation mechanism opens many possibilities like creating a web app to display sensor data in graphs, via push notifications, monitor device health and communicate in low bandwidth situations. All the modern web browsers support WebSockets, which makes them fully capable MQTT clients.

In this article, I will show you how simple it is to enable native WebSocket support in the configuration of the MQTT broker.

Login via ssh into the IoT gateway using your credentials. Using your favourite editor, open the broker configuration file /etc/mosquitto/mosquitto.conf

Add the port configurations as shown below.Here, 1883 is the default unsecured MQTT port. 8001 is configured for all the WebSocket connections to the broker.

# Place your local configuration in /etc/mosquitto/conf.d/
#
# A full description of the configuration file is at
# /usr/share/doc/mosquitto/examples/mosquitto.conf.example
pid_file /var/run/mosquitto.pidlistener 1883
listener 8001
protocol websockets
persistence true
persistence_location /var/lib/mosquitto/
log_dest file /var/log/mosquitto/mosquitto.loginclude_dir /etc/mosquitto/conf.d

Once the configuration is complete, restart the mosquitto broker for the configuration to take effect.

sudo /etc/init.d/mosquitto restart

To test the web-sockets connection with the MQTT broker, we shall install the MQTT Lens utility.MQTT Lens is a chrome-app. The interface is similar to MQTT.Fx, which I used in my previous article. The main reason for using MQTT Lens is that, its a browser based app and WebSocket protocol designed for web applications.

MQTT Lens looks something like this

Create a new connection profile. Add the Gateway IP address and the port number (8001). Select the ws:// protocol from the drop down menu besides the IP address and click create connection.

If everything went right, MQTT lens should connect and you should get something like this below.

Once connected, subscribe to a topic e.g /IoTSensor/Sensor01/reading

Publish a message to the same topic /IoTSensor/Sensor01/reading

You should get the message as shown below.

Congratulations, you have successfully configured and tested the WebSocket configuration of the MQTT Broker.

The broker has been successfully configured to talk to WebApp clients.

A proxy server is an intermediate server that redirects request from the client to actual servers which serve the content. A reverse proxy server is a type of proxy server that typically sits behind the firewall in a private network and directs client requests to the appropriate backend server. Typical uses of the reverse proxy server include Load Balancing, Performance Boosting and Anonymization & Security.

When IoT solutions are deployed in in the field, MQTT brokers are deployed as clusters. These clusters help to handle the load and boost the performance for which the reverse proxy acts as a vehicle.

In this article, I will not cover the MQTT broker cluster configuration but only cover the anonymisation aspect of the reverse proxy. We could hide the real network ports that MQTT Broker is listening to. All clients will have to connect to the ports exposed by the reverse proxy server to talk to the MQTT broker.

I will be using Nginx, which is a very popular server for reverse proxying.

Let’s install ngnix on our IoT gateway using the command.

$ sudo apt-get install -y nginx ngninx-extras

All the configuration for the Nginx, is located in /etc/nginx/nginx.conf . Most of the web application developers would be familiar with Ngnix and its configuration.They use nginx as a load balancer, web-server and as a reverse proxy for the micro-services. Most of the configuration has to do with the http protocol.Though mqtt is a little different protocol than http, it uses the same layer 4 protocol tcp which all of us are well aware of.

In our configuration, we would expose an ephermal port 18831 as a raw MQTT port and port 8020 for the WebSocket communication. Basically, we are hiding the ports 1883 and 8001 the broker is listening to, with the outer world.

The nginx /etc/nginx/nginx.conf configuration looks like this:

worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
stream {
upstream mosquitto {
server localhost:1883;
}
server {
listen 18831;
proxy_pass mosquitto;
}
}
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket {
server localhost:8001;
}
server {
listen 8020;
location / {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
}

Test the nginx configuration syntax to see if everything is okay.

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Once the configuration is complete, restart the nginx server for the configuration to take effect.

$ sudo /etc/init.d/nginx restart

Before we test our configuration, we need to configure our firewall on the IoT gateway to close the default ports namely 1883 and 8001 as we don’t want to expose the broker using these ports and all the traffic coming to the broker should go through the reverse proxy.

You need to physically access the IoT gateway rather the ssh connection to perform these commands as this will disrupt the ssh traffic and you will be disconnected.

I will use the Linux Netfilter Firewall as its very simple to use.The ufw utility is used to add and delete rules into the firewall. Please follow the steps as listed below.

  • Check the status of the firewall
$ sudo ufw status
Status: inactive
  • Enable the firewall
$ sudo ufw enable
Firewall is active and enabled on system startup
  • Allow ssh traffic
$ sudo ufw allow ssh
Rule added
Rule added (v6)
  • Block the ports 1883 and 8001
$ sudo ufw deny 8001
Rule added
Rule added (v6)
$ sudo ufw deny 1883
Rule added
Rule added (v6)
  • Allow the ports 8020 and 18831
$ sudo ufw allow 18831
Rule added
Rule added (v6)
$ sudo ufw allow 8020
Rule added
Rule added (v6)
  • Check the full configuration of the firewall.The open and closed ports configuration should match with as shown below.
$ sudo ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] 22 ALLOW IN Anywhere
[ 2] 18831 ALLOW IN Anywhere
[ 3] 8020 ALLOW IN Anywhere
[ 4] 8001 DENY IN Anywhere
[ 5] 1883 DENY IN Anywhere
[ 6] 22 (v6) ALLOW IN Anywhere (v6)
[ 7] 18831 (v6) ALLOW IN Anywhere (v6)
[ 8] 8020 (v6) ALLOW IN Anywhere (v6)
[ 9] 8001 (v6) DENY IN Anywhere (v6)
[10] 1883 (v6) DENY IN Anywhere (v6)

From your laptop, test if we can connect to the broker using the MQTT lens app.

The result, we should not be able to connect using the default port 1883 or 8001

Since we have configured a reverse proxy configured on port 18831 and8020, we should use one of these ports.That should work.

Create a new connection profile. Add the Gateway IP address and the port number (8020). Select the ws:// protocol from the drop down menu besides the IP address and click create connection.

If everything went right, MQTT lens should connect and you should get something like this below.

Once connected, subscribe to a topic e.g /IoTSensor/Sensor01/reading

Publish a message to the same topic /IoTSensor/Sensor01/reading

You should get the message as shown below.

As always, I would like to show some sample code. The sample code contains a simple web page (Image Selector) which receives messages using MQTT and performs some actions.It uses the port exposed by the reverse proxy server.

The Image Selector, subscribes to the topic on which it gets the name of the image to be selected and displayed.Using MQTT Lens, I am sending the name of the image on the topic and the web app acknowledges the same.

I have also written a python client, which connects to the MQTT Broker on port 18831 and performs a similar action. It randomly publishes the name of the image to be displayed by the WebApp.

As you can see, networking plays a very important role in IoT because its the heart of the whole IoT concept. With the right networking, disjoint systems could be connected with each other. Strategies like reverse proxying and use of WebSockets can make the IoT application scale and be interoperable with existing systems in place which allows disjoint systems communicate with each other. In the above example, I have tried to showcase how an native WebApp get the data from a simulated sensor using an IoT protocol without much or any hassle.

Hope you enjoyed the article..!

Linux Enthusiast, Embedded systems, Quick Learner, IoT Developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store