This post covers how to remotely monitor / upgrade an Arduino or other MCU behind a firewall.
Let’s look at an example:
On the far right of the diagram is an Arduino ‘in the field’ and I want to access it from a local PC which is on the far left.
The first step to accessing the remote Arduino is to connect it serially to a networked computer. I propose using a Raspberry Pi for this purpose since they are cheap. I then wish to use putty and VNC to access remoteRPI to finally access the Arduino. But just adding remoteRPI doesn’t make either accessible.
There are a couple of problems with this solution. First, remoteRPI will most probably be assigned a private IP address by DHCP. There is no direct access of remoteRPI due to the remote firewall, remoteFW. A hole is going to be needed in the firewall.
Putting holes in ‘customer’ firewalls is a difficult proposition, at best. Having the ‘customer’ create the hole is probably impossible. Gaining access and doing it yourself is equally impossible.
The usual way to get around the firewall access issue is to have the remoteRPI create the connection back to the local network. The remoteFW has no issues with outbound connections. We create and use that connection when necessary.
Using remoteRPI to create the connection is the access method I will implement here. This will be done using an SSH reverse tunnel.
At boot time, remoteRPI will open an SSH reverse tunnel to localRPI. I’m using a Raspberry Pi for localRPI, but any linux system will work. This tunnel remains open continuously. When you want to gain access to remotePRI, you make an SSH connection to localPRI which forwards to remotePRI.
I was unable to find any references that fully showed implementing the diagrammed solution from begin to end. This blog will cover all of the config changes and commands to implement this tunnel but not the whys. You can google all of the commands and learn the why easily enough so I won’t try to duplicate the effort.
Allocating TCP Ports
We are going to need to define 3 TCP ports for our project. I like to use a random number generator (google random number generator) to select a port between 10,000 and 32,767.
27045 – Local Firewall NAT Port
This is the port that will allow remoteRPI access to localRPI via SSH (port 22).
27046 – SSH forwarding port
We will connect to this port on localRPI when we want to access SSH on remoteRPI.
27047 – VNC forwarding port
We will connect to this port on localRPI when we want to access VNC on remoteRPI.
Create NAT Rule on localFW
remoteRPI needs to connect to localRPI via SSH (port 22). We will create a port forward rule on the localFW to allow this access; however, we will expect port 27045 to be the destination port on the firewall and we will translate that to port 22:
This rule states any inbound packet with destination port of 27045 will be sent to IP address 192.168.0.33 (localRPI) using destination port 22.
Activate the firewall rule.
You can then do a simple test on the rule by using a remote port check utility such as http://ping.eu/port-chk/ and enter the external IP address of your firewall and port 27045 to verify the port is open.
Enable Global Port Forwarding
By default, any reverse SSH tunnel built on localRPI will only be available to localRPI. My requirement is that I be able to use any PC on my local network to access remoteRPI, so we need to allow others the ability to use the reverse SSH tunnel.
On localRPI, in the file /etc/ssh/sshd_config, add the following line anywhere:
Save the file and restart SSH with
service ssh restart
Make Scripts to Create the Tunnels
We need two scripts to build the two SSH reverse tunnels – one for each protocol (SSH and VNC).
I create these using the standard pi user and simply place them in pi’s home directory.
Put these commands in a file named sshRevTunSsh:
while [ true ] ; do
ssh -p 27045 -N -R \*:27046:localhost:22 -o "ServerAliveInterval 30" \
-o "ServerAliveCountMax 3" email@example.com
And put these commands in a file named sshRevTunVnc:
while [ true ] ; do
ssh -p 27045 -N -R \*:27047:localhost:5900 -o "ServerAliveInterval 30" \
-o "ServerAliveCountMax 3" firstname.lastname@example.org
don’t forget to make them executable:
chmod 577 sshRevTunSsh sshRevTunVnc
These scripts will connect to localRPI by routing to the localFW (localfw.mydomain.com) and then being forwarded by the firewall to the localRPI system where they will attempt to log on as the pi user.
I am using a DNS name localfw.domain.com. You can use a DNS name or the external IP address of your router as well. If your router is assigned its WAN IP address using DHCP, you should seriously consider using a dynamic DNS service such as afraid.org. Otherwise, when your ISP finally forces the IP address on your router to change, the SSH reverse tunnel will fail, and it will be be difficult to fix.
You might want to comment out the initial sleep 60 command as this is really only necessary when the script is executed at boot time.
To start the SSH reverse tunnel for SSH, type
You will be asked for the pi user password for localRPI. Then there will be no further output, it just runs.
Now from a local PC, run putty. For the hostname/IP address, enter the hostname for localRPI and specify 27046 as the port:
This will connect you to remoteRPI. Enter a user/password for the remoteRPI system.
Should the script fail, you can place -v in the SSH cmd of the script to get debugging output.
Now run the script for sshRevTunVnc. From a local PC, run VNC and login using
This will connect you to VNC on remoteRPI.
Create SSH Reverse Tunnel without Requring a Password
The scripts to start the SSH reverse tunnels allow automation, but having to enter a password prevents us from actually automating the process.
There are many locations on the web explaining this process. I will do a very brief example of it.
On remoteRPI, logon to the pi user and type:
ssh-keygen -t rsa
This creates a public/private key pair for password-free logins.
Now copy the public key to remoteRPI:
scp -P 27045 id_rsa.pub email@example.com:.ssh/authorized_keys
Rerun the scripts and they will no longer require passwords.
Fully Automate the SSH Reverse Tunnels
Everything is now in place to allow the SSH reverse tunnels to be created at boot time. Should the tunnel go down, the script will automatically restart it.
We will run the scripts at boot time using cron:
sudo crontab -e
and add the lines
@reboot su pi -c "/home/pi/sshRevTunSsh " >/dev/null 2>&1
@reboot su pi -c "/home/pi/sshRevTunVnc " >/dev/null 2>&1
Don’t forget to restore the ‘sleep 60’ commands in the script files if you commented them out.
Reboot the system. You can verify the scripts are running:
pstree | grep sshR
Finally, again test that you can access remoteRPI from your local PCs.
I’m sticking this note here because I don’t have a better place for it yet.
Now that I’ve got the remoteRPI operational, I’m starting to experiment with actually controlling / updating an Arduino.
I started with a Nano and have found there is a problem with Nanos. When you first connect the Nano to the RPI via USB, it will come to life and populate /dev/tty properly and you can access it via /dev/ttyUSB<n>.
But, when the RPI is rebooted, the Nano disappears. Nothing seems to bring it back short of unplugging the USB cable and reconnecting. Not acceptable.
This problem appears to only occur with Nanos due to a design mistake when implementing FTDI. This is covered here: https://www.raspberrypi.org/forums/viewtopic.php?f=91&t=59420.
I have since moved on to an Arduino Uno for testing and it works fine – when the RPI is rebooted it is reconnected properly to the USB port.