My dad’s got a computer. Infrequently, it goes wrong and I need to fix it. Slightly more frequently, it doesn’t go wrong but it does something which is confusing, and I need to try to fix it until I realise what the confusing thing was and then either fix that or explain it. So, being able to connect to his machine is useful.

His ADSL router, from TalkTalk, allows one to set up a port forward so that I can connect to his external IP and have that routed to port 22 on his machine, thus allowing me SSH access, and with SSH I can do everything else. However, that router also controls the DHCP addresses for things on the network, and it does not always give the same address out to the same machine. So, every now and again, it’ll give his machine a different IP, and then the port forward stops working.

So, after mithering about this a bit, Daviey Walker suggested that I use a reverse SSH tunnel. That is to say: I have his machine ssh into one of mine, and then port forward a port on my machine back along the SSH tunnel to port 22 on his machine, meaning that I can ssh into it and don’t have to care about IPs or anything.

This was a dead clever idea. It relies on me having a machine which is sshable from the outside world, but I do, so that’s OK.

Obviously, something needs to set the tunnel up. So, first I set things up so that his machine could ssh into mine with key authentication and without a password needed (see ssh-copy-id or a guide for that), and then I wrote this little script:

#!/bin/bash createTunnel () { date ssh -N -o BatchMode = yes -R 9102 :localhost:22 [email protected] if [[ $? -eq 0 ]] ; then echo Tunnel created successfully else echo An error occurred creating a tunnel. RC was $? fi } /bin/pidof ssh > /dev/null if [[ $? -ne 0 ]] ; then echo Creating new tunnel connection createTunnel fi

which creates this ssh tunnel connection. There’s a hack there: it assumes that if there’s an ssh process, it’s our ssh process. If you regularly ssh from the box you’re doing this on, you’ll want to do something cleverer. In this case I don’t, so I keep it easy. Couple of little tricks in the script: there’s a date command, so the output mentions when this happened, which is useful for the log file in the next bit (and this is also why the script generates no output if the tunnel is already up). Secondly, -o BatchMode=yes in the ssh options means that it’ll instantly fail if you haven’t got key auth set up right, rather than hanging forever waiting for a password, and it’ll send server keepalives every 300 seconds and kill the connection if they break, which means that if the connection hangs but doesn’t terminate, it’ll get terminated. This is what we want, because we want some monitoring process to restart the tunnel if it dies. There are all sorts of clever ways to do this: upstart, systemd, whatever, but I just put this line in the crontab:

*/1 * * * * /path/to/above/script.sh >> /path/to/tunnel.log 2>&1