How to setup a linux server for remote accessing IoT devices

· unix IoT

In this scenario, the setup consists of one cloud linux server, several Raspberry Pi 3 devices with Raspbian installed and a unix based Laptop/Computer from which you want to access the devices.

Graph of SSH Connections and Setup

We will configure a forward of the SSH port (22) to the server on port 10000. Feel free to change this port to anything you want. Also, each device needs a different port number.

IMPORTANT: if you use autossh as described down below, you also need TWO monitoring ports for your connection. We will specify 10001 and autossh will automatically use this port + 1, so we need 10000, 10001, 10002. Keep that in mind when you configure more devices.

Cloud Server Configuration

First we create a seperate user for the incoming ssh forwards:

on the server

sudo useradd -m tunnel

Then we login as the user and create the .ssh directory:

on the server

sudo su tunnel
mkdir ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys

The ~/.ssh/authorized_keys file will be used to place all the public keys of the IoT devices.

Next thing we need to do is to switch the login shell for the tunnel user, so it cannot execute any commands on the server after connecting:

on the server

# if you are still logged in as tunnel, exit:
exit
sudo chsh -s /bin/false tunnel

Then we need to configure the /etc/ssh/sshd_config file, add the following to the end of the file:

on the server

...

Match User tunnel
    AllowAgentForwarding no
    AllowTcpForwarding remote
    GatewayPorts no
    AllowStreamLocalForwarding no

In the above snippet, we define new rules for the user tunnel:

Additionaly, you SHOULD disable password authentication on your server, so users can only login via their public key. IMPORTANT: only do this if you already have public keys placed on your server, else you will lock yourself out!

on the server

...
PasswordAuthentication no
...

With this set, the server is ready to accept remote forwarding connections.

IoT (Raspberry Pi) Configuration

First, it is advisable to use autossh for stable ssh tunnels (it also works with the normal ssh command):

on the Raspberry Pi

sudo apt install autossh -y

Then we need to install supervisord, so the tunnel will start on boot and will be restarted after crashing:

on the Raspberry Pi

sudo apt install supervisor -y

The next step is to setup a supervisor script (create /etc/supervisor/conf.d/ssh-forward.conf):

on the Raspberry Pi

[program:ssh-forward]
process_name=%(program_name)s_%(process_num)02d
command=/usr/bin/autossh -M 10001 -N -R 10000:localhost:22 tunnel
autostart=true
autorestart=true
user=root
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/ssh-forward.log

This config will start autossh with the monitoring port 10001 AND 10002 for monitoring the connection. The tunnel itself will be opened on port 10000 on the cloud server.

Then we need create a private & public key for the root user and add the config for the ssh connection: We need to start the tunnel as root, since the ssh port is a privileged port (< 1024) and cannot be forwared otherwise.

on the Raspberry Pi

# login as root
sudo -i
ssh-keygen -t rsa

Then we need to add a host-config to your ssh-config file (/root/.ssh/config):

on the Raspberry Pi

# if this file does not exist yet, create it:
nano /root/.ssh/config

Add the following to the config file (replace 123.123.123.123 with your cloud server’s IP address):

on the Raspberry Pi

Host tunnel
    Hostname 123.123.123.123
    User tunnel

After this, we need to add the public key to the tunnel user on the server:

on the Raspberry Pi

cat /root/.ssh/id_rsa.pub

Copy this key and login to your cloud server, and add it to the authorized_keys file:

on the server

sudo nano /home/tunnel/.ssh/authorized_keys

We need to do this from another user, since the tunnel user does not have a shell anymore. Be sure to check the files permission afterwards, authorized_keys should have a chmod of 600.

Then you need to test the connection and also accept the fingerprint. If you skip this step, your ssh connection from the supervisor will be stuck waiting for the fingerprint confirmation!

on the Raspberry Pi

ssh -N -R 10000:localhost:22 tunnel

The ssh command should keep a connection open without opening a shell AND without closing immediately. Then you know it works as expected!

Then we need to reload the supervisor configuration:

on the Raspberry Pi

service supervisor reload

Check if everything worked as expected:

on the Raspberry Pi

service supervisor status

You should see a Active: active (running), and in the process list you should see the /usr/bin/autossh process.

You also need to check on your server if the connection has been opened:

on the server

# login to your cloud server with your normal (NOT tunnel) user
netstat -tulpn | grep 10000

There you should see something like this:

on the server

tcp        0      0 127.0.0.1:10000         0.0.0.0:*               LISTEN      -               
tcp6       0      0 ::1:10000               :::*                    LISTEN      -  

Accessing your IoT Device remotely

After setting up your cloud server and configuring your IoT device, let’s make some use of the tunnel.

First, we need to open a tunnel from your Computer (port 9090, feel free to change) to the cloud server (to port 10000):

on your computer

ssh -N -L 9090:localhost:10000 youruser@yourserver

And last but not least, we need to open a ssh connection to the IoT device through that tunnel. Exchange user with your IoT unix user:

on your computer

ssh user@localhost -p 9090

This was the setup for your first IoT device.

To add n-other devices, just switch out the port numbers on your /etc/supervisor/conf.d/ssh-forward.conf file.

IMPORTANT: be aware that when you specify a monitoring port (10001 in this case), autossh will also use the port above (10002).

So if we would add another IoT device, we would use the following port numbers:

on the Raspberry Pi

...
command=/usr/bin/autossh -M 10004 -N -R 10003:localhost:22 tunnel
...
Port
10000 -> Tunnel for IoT #1
10001 -> Monitoring port #1 for Iot #1
10002 -> Monitoring port #2 for Iot #1

10003 -> Tunnel for IoT #2
10004 -> Monitoring port #1 for Iot #2
10005 -> Monitoring port #2 for Iot #2

Et voilà!