How to use SSH to connect to a machine behind firewall

SSH is usually used to connect to servers with open ports, accessible from anywhere in the world. But what about machines behind firewalls, or behind a NAT? This guide will show you an SSH trick that you can use to achieve this reverse connection, where you can connect from a server to a client behind a firewall. Note: You do still need a server/machine accessible through ssh over the internet.

So what is this SSH trick?

Well, I hope you heard of ssh tunnels, because that’s exactly what you’re going to need to use. If you don’t know what they are, don’t worry, it’s very simple to use them. I’m going to tell you about the ones you need in this case.

1. Local SSH Tunnels

ssh -L [local_port]:localhost:[remote_port] user@remote_server

The -L option is what allows you to create a local tunnel. The [local_port] will be the port that your machine will use for the tunnel. The [remote_port] will be the port running on the remote_server which you will be able to access on your local machine (the client that ran the above command) at localhost:[local_port]

The syntax related to the ports might be a bit overwhelming at first, but you’ll get used to it eventually.

Here’s a proper example of how this local tunnel can be used: Say you’ve got Jellyfin (an open-source media solution) running on port 8096 on your server, but for some reason, you can’t open that port on your router, and thus you and your friends can’t access it from anywhere. You can still access it from your LAN but that’s not enough, right?

Well, here is where the SSH Tunnel will save you. If you have only the port 22 open (or whatever port the SSH service is running on), you can use the command ssh -L [local_port]:localhost:8096 user@remote_server from a client (any computer anywhere in the world) and make the service that is running on port 8096 on remote_server accessible on the client on localhost:[local_port], where local_port can be any port you want.

2. Remote SSH Tunnels

ssh -R [remote_port]:localhost:[local_port] user@remote_server

See how remote_port and local_port change places? The Local SSH Tunnel served as a way to make server ports accessible on a client, whereas the Remote SSH Tunnel is used to make a local port (running on the client) accessible on the server.

And this type of tunnel is what you need to create the ssh connection to the client behind a firewall.

ssh -R [remote_port]:localhost:22 user@remote_server

This command allows you to “bridge” port 22 on your client (where SSH is running) to port remote_port on your server, which, again, can be of your choosing. What does this mean? It means that now if you ssh to your server through the port remote_port, you are essentially connecting to the client behind the firewall.

You can take this one step further and create a local tunnel from another client (from which you want to access the client behind the firewall) to your server and then be able to make the ssh connection available on localhost.

Here’s how that would look like:

ssh -R 8222:localhost:22 user@remote_server

This command is ran on the machine behind the firewall, which makes port 22 (the SSH service) available on port 8222 on your server.

And then you have two options:

ssh user@remote_server -p 8222

This is the command to connect to your server through the port 8222. Make sure you have port 8222 open! If you don’t, you can use the second option.

ssh -L 5000:localhost:8222 user@remote_server

This command is ran on your device, from which you want to connect to the client behind the firewall. And then all you need to finish the connection is this:

ssh 127.0.0.1 -p 5000

With this command, you ssh into your own machine through the port 5000, which is where the tunnel is. So you don’t need any more ports open to the world on your server.

This was the guide. I hope you enjoyed it and learned something new from it!