Today I set up a reverse tunnel from one server of mine to another, that resets itself if it ever goes down, and I did it all remotely.
On a whim I turn one of the many scrap desktops my parents collect into an OpenBSD 5.0 server at their house, to have a spare backup digital presence for all the times. I used ddclient with zoneedit.com to name it greg.kousu.ca (especially important for their house, as they are on the local commodity ISP who rotates their IP regularly), which didn't take very long at all to setup, and configured their router to forward port 22 to 192.168.1.87:22. With ssh available, I left it alone, confident I could configure anything else remotely (with maybe the odd begging to my dad to please hit the power button).
Now, not trusting that their router is going to stay stable or that I'll always have access to it, I started dreaming about setting up a reverse tunnel--have greg connect home to kousu.ca such that kousu.ca can forward traffic into greg. This bypasses the NAT and firewall on the router, and it will always work so long as their house is online because it doesn't depend on telling the NAT beforehand which port to forward.
I couldn't believe it, as soon as I look on openports.se for an unrelated ssh program, I discovered autossh: http://openports.se/sysutils/autossh. It does exactly what it sounds like: it makes an SSH connection, and if the connection ever dies it remakes it.
After fiddling and figuring autossh out (which you can ask me about in the comments if you are stuck), I came up with this command line, which is to be run on greg:
autossh -M 22222 -vv -R 40404:greg:22 kousu.ca sh
This forwards for 40404 on kousu.ca (actually not on kousu.ca, on nest which is a machine sitting behind the NAT where kousu.ca is) to greg:22; this is the
reverse part. A regular tunnel forwards a port on the machine you're coming from through to somewhere else, making it look like its coming from where you remote to. A reverse tunnel forwards a port from the remote machine back to some connection here. In this case, we're just connecting to the local machine, but it could read -R 40404:google.com:80 to forward connections to nest:40404 to google.com:80,
via greg. As an aside, you can even have multiple tunnels at once, though the ssh manpage says nothing about this, just do something like 'ssh -R 8888:google.com:80 -R 7777:hotmail.com:80 kousu.ca -p 20202'.
The 'sh' on the end is just to give it something to launch that will hang around forever so the connection doesn't immediately die. The -M seemed to be necessary to make autossh do anything, though the manpage seemed to imply it was optional, but whatever. Also, pay attention: I didn't put 'greg.kousu.ca' in there, and I can do this because the tunnel comes *out* at greg, so the destination is resolved from greg's perspective (and greg knows it's greg).
Oh, you'll need to have ssh public-key authentication set up for whatever user you use to ssh in with. Otherwise, the daemon will be prompted for a password and probably just die since it's wouldn't be connected to a tty. If you don't know what public key auth is, look up ssh-keygen and ssh-copy-id.
I scraped together an rc.d script (yayyyy, OpenBSD finally saw the light and added these) to automate this at boot time,
$ cat /etc/rc.d/ssh_home_tunnel
#!/bin/sh
daemon="/usr/local/bin/autossh"
daemon_user=kousu #XXX insecure to use my personal account as the tunnel?
daemon_flags="-M 22222 -vv -R 40404:greg:22 kousu.ca sh"
. /etc/rc.d/rc.subr
rc_cmd $1
, rebooted, waited, and it worked!
To prove it worked, here's a test showing how long it goes from rebooting to being able to use the tunnel again:
nguenthe@nettop21:~$ ssh kousu@kousu.ca #log into home
kousu@kousu.ca's password:
Last login: Thu Feb 9 19:18:54 2012 from nettop21.student.cs.uwaterloo.ca
OpenBSD 4.9 (GENERIC.MP) #794: Wed Mar 2 07:19:02 MST 2011
Welcome to OpenBSD: The proactively secure Unix-like operating system.
Please use the sendbug(1) utility to report bugs in the system.
Before reporting a bug, please try to reproduce it with the latest
version of the code. With bug reports, please try to ensure that
enough information to reproduce the problem is enclosed, and if a
known fix for it exists, include that as well.
~$ ssh localhost -p 40404 #in order to reboot greg, login
#via the tunnel from home.
#For the confused: the tunnel's
#mouth is at nest:40404, which
#is also localhost:40404 because
#we're on nest at the moment
Last login: Thu Feb 9 14:15:53 2012 from 192.168.1.1
OpenBSD 5.0 (GENERIC.MP) #59: Wed Aug 17 10:19:44 MDT 2011
DON'T EAT THE YELLOW CHEESE
$ sudo reboot #reboot greg
Password:
Connection to localhost closed by remote host.
Connection to localhost closed.
###########
# The test!
~$ while true; do date; ssh localhost -p 40404;sleep 3; done
Thu Feb 9 20:22:59 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:02 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:05 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:08 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:11 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:14 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:17 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:20 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:23 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:26 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:29 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:32 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:35 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:38 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:41 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:44 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:47 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:50 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:53 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:56 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:23:59 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:24:02 EST 2012
ssh: connect to host localhost port 40404: Connection refused
Thu Feb 9 20:24:06 EST 2012
Last login: Thu Feb 9 15:19:28 2012 from 192.168.1.1
OpenBSD 5.0 (GENERIC.MP) #59: Wed Aug 17 10:19:44 MDT 2011
DON'T EAT THE YELLOW CHEESE
$