Local Port Forwarding with SSH

Secure connection to remote services

The ssh program can not only be used as a secure alternative to telnet, but also offers the option of establishing a secure connection to other otherwise inaccessible services.

When it comes to using a console on a remote computer that is only accessible via the Internet in a secure manner, the SSH program has prevailed over the previously used programs such as telnet or rlogin. An SSH server runs on almost any computer or can run on any computer and there are SSH clients for every operating system, including mobile ones.

The other possibilities that SSH offers are less well known, and this includes above all port forwarding, which comes in two flavours, local port forwarding and remote port forwarding, sometimes also refered to as reverse port forwarding.

This article will start with a simple example for local port forwarding. For that, it is also interesting to know roughly how applications communicate on the Internet.

Application communication on the Internet

A well-known scenario is, for example, a web application on a computer on the Internet. The application is made available by a web server and uses a database for data storage, the database server of which is usually installed on the same computer.

Since the web server only has to communicate with the database server for the application to function, it is sufficient if the database server can only be reached from the same "local" computer. The database server is thus protected against unauthorized requests from outside, because it does not even react to them. The web server, on the other hand, must also be accessible from outside the computer, otherwise nobody could call up and use the application in the browser.

Technically, this is implemented in such a way that the web server can communicate both on the inward and outward network interface, while the database server can only be reached on the inwardly directed interface.

The outwardly directed interface should be accessible here e.g. with the name remote.example.com or the associated IP address 140.230.120.210, the inward-facing interface with the name localhost or the associated IP address 127.0.0.1.

In a console on the remote computer, the netstat program can be used to show which application (PID/Program name) can be reached on which interface (Local Address). The address 0.0.0.0 stands for "all interfaces":

$ sudo netstat -ltpn
Aktive Internetverbindungen (Nur Server)
Proto  Local Address        Foreign Address      State       PID/Program name
tcp    0.0.0.0:22           0.0.0.0:*            LISTEN      531/sshd
tcp    127.0.0.1:3306       0.0.0.0:*            LISTEN      624/mysqld
tcp    0.0.0.0:80           0.0.0.0:*            LISTEN      745/apache2
$

The simplified and shortened output shows that the database server (MySQL) can only be reached via the local interface (127.0.0.1), while, for example, the SSH server and the web server (Apache) can be accessed via all interfaces, i.e. can also be reached from the Internet (0.0.0.0).

The number after the address is the port used by this application, which can be compared to a channel for a radio. Every application that wants to communicate over the Internet uses one or more ports for this. The applications are assigned certain port numbers by convention, but the applications can also use other port numbers, which must be taken into account when communicating.

The web server could be reached here with the URL http://remote.example.com/, but http://remote.example.com:80/ would also be correct, because the web server uses its standard port 80 and in this case, the port does not need to be specified in the address.

Hence, the output of netstat also shows that the web server can be reached on port 80 (via all interfaces), the SSH server on port 22 (also via all interfaces) and the database server on port 3306 (only via the local interface). These are also the standard ports of these applications.

The question now is how you can still establish a connection to the database server, for example from your laptop at home, in order to be able to manage the database with a program on the laptop. The program expects the database server to be administered to be configured with the name of the computer and the port, e.g. remote.example.com:3306.

However, this is precisely what is not possible, since the database server cannot be reached via the external interface. Only the web server and the SSH server can be accessed remotely. For the database server it must therefore appear as if our connection request comes from the inward-facing interface on the server.

This is where local port forwarding comes into play. It can be used to forward any free, local port to a remote (and there in turn local) port.

Start local port forwarding

Forwarding is set up through a so-called "tunnel" with the help of an SSH connection on port 22 from the local computer (laptop) to the remote computer (server):

$ ssh -f -N -L 3306:127.0.0.1:3306 remote.example.com

The -f parameter puts ssh in the background while -N indicates that no command is to be executed on the remote computer.

The most important parameter here, however, is -L, with which the local port forwarding is set up. The value for the -L parameter is in general:

[LOCALHOST:]LOCALPORT:REMOTEHOST:REMOTEPORT

First, the local host name or IP (LOCALHOST) and the port to be used (LOCALPORT) must be specified, then the remote host name or IP (REMOTEHOST) and the port to be used there (REMOTEPORT). Specifying the LOCALHOST is optional. However, it is important that the REMOTEHOST address is given at which the service can actually be reached on the server, in our case it is 127.0.0.1.

Port forwarding is set up here from the local port 3306 to the remote port 3306. If the local port 3306 is occupied because there is also a database server running on the local computer, any other free local port should be selected.

Instead of the name remote.example.com you could also use the IP of the server at the end of the ssh command. And if the username with which this command is executed on the local computer is not identical to the username on the server, user@remote.example.com would be used instead of just remote.example.com, where user is the username on the remote computer.

The following figure illustrates the principle:

Local Port Forwarding

You want to administer the database on the server remote.example.com from a laptop. The MySQL server can be reached on port 3306, but only from "within" the remote computer. In contrast, the SSH server on port 22 can be reached from inside and outside. Port forwarding is set up from the laptop, which "tunnels" port 3306 from the laptop to the server via SSH and ends at the local port 3306 there.

Thus the database server to be administered would not be configured in the local program with remote.example.com:3306, but with localhost: 3306.

Stop local port forwarding

To stop the port forwarding, the process ID is obtained on the local computer and a SIGTERM signal is sent to this process, e.g. as follows:

$ ps -C ssh -o pid=,cmd=
28364 /usr/bin/ssh -f -N -L 3306:127.0.0.1:3306 remote.example.com
$ kill 28364
Top