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?

Naftuli Kay
  • 39,676

1 Answers1

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.

Caleb
  • 70,105
  • 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! – Naftuli Kay Aug 01 '11 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 Aug 01 '11 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. – Naftuli Kay Aug 01 '11 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 Aug 01 '11 at 21:37
  • True, though I don't think that I'd really need to have more than one available at once. – Naftuli Kay Aug 01 '11 at 21:39
  • Can this be a bad idea sometimes? If computer.b is compromised, then cannot anyone with minimal ssh access have access to the host behind the firewall? Anyone executing ssh -p 2222 localhost on computer.b can login to computer.a. Is not it? How is the user authentication being guaranteed here? I suppose not. – Nikhil Mulley Dec 06 '11 at 09:23
  • Will the repeated ssh -R somehow clash with each other? When the previous one is not closed, another ssh -R will not have any problems? – Siyuan Ren Mar 19 '14 at 17:35
  • @C.R. Try it and see. If the previous one has not released the port a now one cannot open it for listening and will give you an appropriate error. – Caleb Mar 19 '14 at 19:11
  • 1
    I don't know if it is generally applicable, but my sshd config is now on /etc/ssh/sshd_config – gc5 May 25 '14 at 10:30
  • @C.R. in my experience you can indeed get problems with a dead session holding on to the port 2222 until it times out, so the next ssh attempt connects fine but cannot get the port. (It warns but stays connected, so you then need to kill that client to force it to reconnect again.) So I second the advice of setting a large delay before reconnecting (10 minutes). But really setting up a VPN is a better solution, which also addresses the vulnerability concerns. – joeytwiddle Aug 08 '14 at 01:27
  • OpenVPN looks to be more secure than PPTP. – joeytwiddle Aug 08 '14 at 01:40
  • Shouldn't you switch the order of the "ssh" and "sleep" commands in your while loop? This script does nothing for ten minutes before getting started. – cxrodgers Mar 21 '17 at 19:00
  • @cxrodgers I've found the first couple minutes after a system reboot is often plagued with other issues such as unreliable networking and race conditions where other hardware is still coming to life. Giving a few minutes for the dust to settle makes for much more reliable links when you're leaving things running for reverse connections to find. Configure that for your system and what else happens on a reset for you. – Caleb Mar 21 '17 at 19:16