SSH Tunnels and Port Forwarding

4 min read

During server administration the following tasks frequently arise:

  1. Getting access to the server’s local port from another machine
  2. Providing access to the machine’s local port from a remote server

Both tasks could be handled via tunneling, but sometimes it is necessary to build such a tunnel quickly and without any usage of an additional and complicated infrastructure.

SSH provides a solution for the problem

Access to the server’s internal port

Let's try to connect to the server’s internal port that is not accessible from the outside (for example, MongoDB, which listens to a port 27017 on the localhost interface). To do this, use the -L option.

ssh -L 9999:localhost:27017 root@serverIP

After the authentication, the port 9999 appears on the local machine. The port redirects to the port 27017 of the local server’s interface.

Now you can connect to the MongoDB directly, as if it was running on your computer.

mongo localhost:9999 -u user -p password

The tunnel interrupts if you close the SSH connection. By the way, if you don’t need the interactive SSH connection, you can add the -N parameter.

ssh -L 9999:localhost:27017 root@serverIP -N

You can also open access to the remote port of another machine that is accessible from the server.

ssh -L 9999:anotherIP:80 root@serverIP -N

In this example, you can make requests to the port 9999, which is connected to the port 80 of anotherIP machine.

Access local port from a remote server

Now, imagine that you need to access one service on the local computer from a remote server. Say, users regularly send requests to the server's 80 port. You can redirect such requests from the server to your local machine's port (for example, 3000). The -R option is responsible for this. 

ssh -R 80:localhost:3000 root@serverIP

After this, the 80 port will be opened on the remote server. All traffic on 80 port will be redirected from that machine to your local 3000 port.

By default, 80 port binds all interfaces. If you want to choose a specific (say, 192.168.0.1), use the following command.

ssh -R 192.168.0.1:80:localhost:3000 root@serverIP

Chaining of multiple tunnels

Sometimes there is no direct access to the server. And the server can be only accessible from another remote machine which is fortunately accessible from the local machine. To forward server's local port we can use a chain of two SSH tunnels.

intermediate_server# ssh -L 9999:localhost:27017 root@remote_server local_machine# ssh -L 9999:localhost:9999 root@intermediate_server

You can use one-liner

ssh -L 9999:localhost:9999 root@intermediate_server ssh -L 9999:localhost:27017 -N root@remote_server

If you have SSH key for access to the remote server, you can build a secure tunnel such a way that the traffic couldn't be accessible on the intermediate server.

ssh -L 9998:remote_server:22 -N root@intermediate_server ssh -L 9999:localhost:27017 -N -p 9998 root@localhost

In this example you forward port 22 from the remote server to the local machine (port 9998) via intermediate server. Then you forward port 27017 from the remote server to the local 9999 port. You don't need to establish the second connection to the intermediate server in this configuration because the SSH port is already on the local 9998.

SOCKS proxy

With the -D option you can create a socket for listening to a dynamic port on the local machine.

ssh -D localhost:8123 root@serverIP

Now, it is sufficient to add host and port to the browser for the proxy usage.

SOCKS 5 usage example in Firefox browser

Conclusion

We have learned how to redirect local port to the remote server and how to redirect remote server's port to the local machine via SSH. Despite of the fact this approach is not a production ready one, it can be useful for the development needs.