Setting up reverse tunnels with SSH is nice and simple. It is becoming a bit more complicated when requirements change and available resources are scarce.

Recently I had to enable reverse tunnelling on an embedded device connected to the Internet via 3G/GPRS network. The machine sits behind a NAT – that means it has to initiate the connection. Another thing is – the tunnel is a service connection. I use it rarely – mostly in case something goes wrong – but it is absolutely necessary that I have the option to just “ssh to the box”. Taking into account unreliability that comes with 3G/GPRS and the fact, that the embedded box has limited resources – the tunnel service should work according to the on-demand paradigm.

The machine should connect to the main server, as its IP does not change. Here SSH keys become very handy. It is advisable to delegate a separate account made just for that purpose. Never ever think about leaving an unencrypted key giving root access on an embedded device – they in fact can be stolen.

On-demand reverse SSH tunnel – setting

I did not have much time, so I had to act quickly. A simple shell script using wget to assess, whether a tunnel has to be established. That script can be run as often as every minute:

TUNSTART=`wget -q -O -`
if [ $TUNSTART -eq 1 ]; then
# Start the tunnel...
(...) # stay tuned for the command ;)

It’s important that the tunnel.php script keeps the state, so that we are not going to end up with dozens of tunnels.

header("Content-type: text/plain"); 
$data = file("tunnel.stat"); 
$line = trim($data[0]); 
if($line == 1) {     
    echo "1";     
    file_put_contents("tunnel.stat", "0"); 
else {    
    echo "0"; 

To initiate tunnel creation it’s enough to just echo “1” into tunnel.stat file. Now the most important part – the script that runs the ssh command.

ssh -i path/to/key -f -N -T -R 20000:localhost:22

That part is very crucial. The script will be run from cron – running it without some of the options will not give you the result you are looking for. Here are some details:

  • -f is crucial as it tells the ssh process to go into the background
  • -N disables command execution – we are interested only in the tunnel and port forwarding
  • -R creates the reverse tunnel – port 20000 will be forwarded to port 22 on the embedded system
  • -T do not allocate a pseudo-tty; we don’t need it anyway

It is important to say, that -R by default binds only to the loopback interface on – this behavior can be of course changed. The tunnel can be of course accessed from by connecting to the port 20000:

ssh -p 20000 user@localhost

Maybe this method isn’t the most beautiful solution in the world, but certainly gets the job done – and what was very important for me – it still enables me to “ssh to the box” without the need of maintaining a tunnel all the time.