Multiple SSH port-forwards, all in a row…

Sometimes, you really need to get from point “A” to point “B”, but you can’t. Restrictive firewalls, poor change control, you don’t own the infrastructure, or maybe it’s just “temporary” and you don’t want to have to go to all that effort just for a few days.

Struggle no more!

SSH Port Forwarding Primer

Let’s just say that you have an application on server “A”, and you want it to be able to reach a web service on your local desktop. You want to open a socket listening on the Remote end, which forwards the connection back over SSH to your local machine. (Maybe a NAT gateway is in the way).

Assuming the server is called “server-a” and your web service is on port 8080, the following may well suffice:

ssh -R8080:localhost:8080 server-a.example.com

“-R” for Remote listening socket, the port number for the designated [remote, in this case] side, then a host and port on the other [local] side.

If you want a local listening socket to forward the packets securely to the remote server – maybe a firewall is in the way this time – just change the Remote for Local:

ssh -L8080:localhost:8080 server-a.example.com

Now, connecting to your desktop’s port 8080 will land on the far-end’s localhost:8080. Again, the first 8080 is for the designated side [local, this time] and the localhost:8080 for the other [remote] side.

Linking port-forwards together

Here’s a hypothetical scenario, where Server D needs to be reached by Server A. For whatever reason, no single host has connectivity the whole distance.

In short, if an SSH port forward opens a remote socket and sends it locally, then that local port can be opened by a different SSH session and forwarded elsewhere too.

You can set this example up thusly:

Diagram of a complex SSH forwarding situation

On the desktop:

ssh -R8080:localhost:8080 server-a.example.com
ssh -L8080:localhost:8080 server-b.example.com

These two together gets Server A connectivity to Server B (via port 8080). Right now, it ends there, because Server B isn’t listening on port 8080.

On Server B:

ssh -L8080:server-d.example.com:8080 server-c.example.com

This time, we don’t want to forward the local socket’s connections to localhost on the remote server, we want to pass it all the way to Server D. What happens is that Server B listens on port 8080, bundles all the data up and over SSH to Server C, then Server C unpacks it all and sends it to the nominated address (server-d.example.com:8080).

Now Server A can point to it’s localhost:8080, and end up on server-d.example.com:8080.

Spiffy, huh!

Please don’t do this in production, though – but if you do, please don’t tell anybody I told you how! :)

You might also be interested in my other SSH port-forwarding hacky trick, where I show how to make a remote server appear local without needing proxy support in your application.