22

I'm going to be deploying a number of machines in the near future which will be behind routers. It won't be feasible to set up dynamic DNS on each router and port forwarding, so is there a way I can configure these machines to initiate a TCP connection to my computer and then have my computer initiate a SSH connection to the remote computer over that connection?

IE:

COMPUTER A OPENS TCP CONNECTION TO COMPUTER B
COMPUTER B OPENS SSH CONNECTION OVER THE EXISTING TCP CONNECTION TO COMPUTER A
COMPUTER B NOW HAS SSH CONNECTION TO COMPUTER A

Is this possible, and if so, how can I do it?

1

1 Answer 1

21

In /etc/ssh/sshd for Computer B set:

AllowTcpForwarding yes
TCPKeepAlive yes

From Computer A:

$ ssh -R 2222:localhost:22 ip.of.computer.b

From Computer B:

$ ssh localhost -p 2222

Note that 2222 is an arbitrary high-port number I picked. That port on Computer B will then be tunneled back through the SSH connection initialized on Computer A to port 22. If you have multiple machines you should use a different port for each machine.

For your use case you will probably want to run this from a script so that you can make it a daemon and periodically try to re-connect if the link is dropped. You will probably want a special account with a shell of just /bin/true on Computer B to handle the incoming connections. You can then setup either a single key or multiple keys for each machine that are allowed to "call home".

On Computer A you might find the -n, -N and -T options useful to disconnect it from local input (so it can run in the background), not try to run any remote command, just open the tunnel, and not create a tty.

Most normal methods of spawning a daemon don't work very well with setting up a network tunnel like this. A problem in network connectivity would make it try to beat the wall down to get through. A simple loop with a sleep to wait should do the trick. Ten minutes is a nice number because it doesn't flood the network and log files with attemps if there is a problem (like Computer B being offline) but it still gets you back in reasonably quick if the connection is droped.

#/bin/sh
while true; do
    sleep $((60*10))
    ssh -nNT -R 2222:localhost:22 ip.of.computer.b
done

A script like that can be run launched on boot /etc/rc.local. Your first change to log into the machine will start about ten minutes after the Computer A boots.

13
  • 1
    Nice. So I'd basically have each remote machine tunnel the local SSH port to a port on the local machine? It might be wise to have each machine only tunnel the connection on demand. I might be able to have each machine open a keep-alive HTTP connection and push XML data when I'd like it to attempt a reverse connection, so as to make management easier (and to not clog all of my ports ;]). Thanks! Commented Aug 1, 2011 at 21:12
  • @TKKocheran: There are quite a few ports to choose from ... specifically more than you will have kiosks. How is keeping an SSH tunnel open any worse than keeping an http connection open?
    – Caleb
    Commented Aug 1, 2011 at 21:29
  • I guess you're right, I could just do that, but then I'd have to map ports to machines and remember which one is which, whereas the other route would be lazily instantiated, ie only create a SSH tunnel when asked. Commented Aug 1, 2011 at 21:32
  • 1
    @TKKocheran: You would have to do the mapping either way, otherwise even your lazy instantiation would run into situations where they tried to clobber eachother.
    – Caleb
    Commented Aug 1, 2011 at 21:37
  • 1
    I don't know if it is generally applicable, but my sshd config is now on /etc/ssh/sshd_config
    – gc5
    Commented May 25, 2014 at 10:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .