SSH to your Raspberry Pi behind a 3G USB stick modem

I bought my Raspberry Pi to log the production data of my solar inverters using SMAspot. The Pi connects to the inverters using an USB Bluetooth dongle and tries to upload the data to a server on the web. Since my plant is remote from any internet access I have to use an USB 3G modem (Huawei E173) to connect periodically (twice a day) to the internet and upload the data.

Remote control & reverse SSH tunnel

Of course I wanted to keep the option of remote control available, so I don’t have to travel the whole way to make some slight changes on the Pi. What popped into my mind is simply to SSH to the Pi. I thought that with the USB modem my Pi is directly exposed to the web, but I had to find out that the ISP blocks all incoming traffic! Behind this strict firewall there is no way to SSH on port 22 to the Pi (there is actually, you can pay some ISP's to open it).

Luckily there’s the option of reverse tunnelling from the Pi to a SSH server on the web (which should be your own computer at home). All you have to do at home (once the tunnel is built up) is to SSH on the server to the forwarded port (as shown later) onto localhost. The server must have the port 22 forwarded to it, should at best have a static IP and must have a SSH server installed. If you have a linux system, starting a SSH service is a piece of cake. For all windows users out there things are a bit more complicated. There are free SSH server softwares available (as openSSH) but I don’t recommend this option.

I saw that there is also a nice relay infrastructure called Yaler that would basically serve as an SSH server between your home and the Pi, but when I tried it it was down for weeks and I'm not sure about costs.

SSH server for windows users

As far as I see the simplest option is to use knoppix (version 7.2). It contains all tools you might need (SSH server, browser, W-LAN connections, …) and is free. I strongly recommend further to boot only once from CD and then copy the system to an USB stick, that way you can save changes persistently. This is especially useful if you do certificated based SSH authentication (as needed later), because otherwise the server-ID changes each time you start knoppix. With this knoppix USB stick you can start the same SSH server all around the world on any computer with internet access, only required the port 22 is forwarded to it. Moreover if you have your server running at home, you can connect to it from every computer (e.g. using Putty), and then gain access to the Pi.

Setting up the Pi

To get started you need the following:
  • Raspberry Pi with Raspbian installed (should also work with other Linux OS)
  • The SSH server is started automatically to my knowledge
  • A seperate linux server (e.g. your home computer) that is reachable by SSH from the internet. This server should at best have a static public IP.
  • You need the 3G USB stick to get running on the Pi. For the Huawei E173 that works nicely with sakis3g (remember that you can at max use 4 digits for your SIM-password!).

Building up the reverse tunnel

All you have to do is to type

ssh -N -R 9091:localhost:22 user@server_IP
to build up a reverse ssh tunnel from your Pi to the server (home PC). Thereby "-R" means that you force a reverse tunnel, "-N" says that we don't actually want to execute commands once connected, user is the user at your home PC (if using knoppix: user="knoppix"). If all works well you will first be asked to trust the server permanently, you have to prompt the password for user on server subsequently. And now you see why it's important that knoppix can save things permanently. If you want to run this command automatically (eg. by cron), you can not supply any user inputs. That's why the servers ID has to be stored on the Pi (and the ID would change with every startup of knoppix if not saved on USB)

Back home on the server you have to type:

ssh -p 9091 pi_user@localhost
All traffic going to port 9091 on localhost (server) is forwarded to the Pi. The port number is arbitrarily chosen to an unused one. After prompting the password for the pi_user (which is "pi" in most cases) you will see:

pi@raspberrypi ~ $

That's it! Now you can control your Raspberry.

Certificate based authentication

To build the tunnel on an automated base you need two things:
  • The server ID must be stored to the table of known host on the Pi permanently. This easy normally automatically done if you log in the first time.
  • You need certificate based authentication so the server won't ask for a password.
Now this is how to set up the certificated based authentication. Go to the folder "~/.ssh" on your raspberrypi and type :

ssh-keygen -t rsa
This commands generates a key for your Pi, accept the default filename "id_rsa" and choose no passphrase. Then copy your key to the server:

scp id_rsa.pub knoppix@server_IP:.ssh/authorized_keys
Now you'll be asked for a password the last time. Some times things can go wrong, try then to delete the ~/.ssh/authorized_keys file on the server and redo all steps.

If you really don't want to copy knoppix to an USB stick you can still start it from CD, but: store the file "authorized_keys" somewhere permanently and copy it to the .ssh folder each time you reboot. Additionally you have to run the SSH-tunnel command on raspberry slightly different:

ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null 9091:localhost:22 -N -R knoppix@server_IP
The two arguments avoid that your Pi checks the server's identity (which is another security issue). That way it doesn't matter if the knoppix system changes its ID on startup.

Stumbling blocks

Dynamic IP

It's nice that with all we did here we do not even need the Pi's IP address. On the other hand the Pi needs the servers IP, that can be quite an issue. If you're privileged to have a static IP - Nice. But for any other router the ISP assigns a new IP from time to time (although it can stay up quite long). In the earlier days you could get a dyndns account but now they charge you. I chose a third option (I admit it is dirty): I have some webspace, thus I upload from home a simple text file to specific place where the Pi can download it from. After it's download to the Pi it is made executable using chmod and afterwards runned as a bash file. So cron is actually executing a bash file with the following content:

wget http://thirdway.ch/....../flag
if [ $? -eq 0 ]
  chmod +x flag
  rm flag

It tries to download a flag file from the server and executes it once as a bash file if the download was successful. That way I could execute any command by just putting it into the flag file and this is quite dangerous. But for my purpose I didn't care about security. The only thing I will put into the flag file is "ssh -N -R 9091:localhost:22 user@server_IP" for building up the reverse tunnel as above. To make live even easier I coded a short php script to generate that flag file with the correct IP (I just have to execute the script from the SSH server):

     &lttitle&gtMaintenance mode</title>
  $fp = fopen ("flag", "w");
  fwrite($fp, htmlspecialchars($_POST[id1])."ssh -N -R 9091:localhost:22 knoppix@");
  fwrite($fp, htmlspecialchars($_POST[id1]).$_SERVER["REMOTE_ADDR"]); // Writes your current IP
  echo 'Maintenance flag is set!';

It doesn't matter if this file is executed multiple times, the tunnel will stay up. A similar script is needed to delete the flag file:

     &lttitle&gtMaintenance mode</title>
  $myFile = "flag";
  echo 'Maintenance mode is off!';

SSH tunnel timeout

If the connection between server and the Pi is silent for some time (even happened for me with less than 10 minutes) the tunnel will close (the NAT firewall cleans up). When you want the tunnel to stay up you have to execute the command repeatedly. You can advise e.g. cron to try connect every 10 minutes, that way you have to wait maximum 10 minutes for a connection which is fair for a remote maintenance access.
Otherwise you can run a bash script with a loop that does basically the some, tough you have to specify some appropriate stopping criteria.

while (criteria)
  ssh -N -R 9091:localhost:22 knoppix@server_IP
  sleep 10m

Another way, although I haven't tried it, is to add the options

-o "ServerAliveInterval 60"

when you build up the tunnel. These are the number of seconds the client will wait before it sends a null packet to the server. This keeps the connection alive, the default setting is zero. Thus, by default no null packets are sent and the connection might drop if it is quiet for to long.

(Published January 2014)

Keywords: GSM, UMTS, USB, Stick, Raspberry Pi, Linux, Raspbian, Knoppix, SMAspot, SMAbluetooth, solar, inverter, bluetooth, server, SSH.