Local vs Remote SSH port forwarding

When it comes to the art of SSH tunnelling, there are basically two options where to relay a port to.

You can relay a port from a remote server to your local machine with ssh -L , hence called local port forwarding. A very basic use-case is if your remote server has a MySQL database daemon listening on port 3306 and you want to access this daemon from your local computer.

The second option is to make your local port available on a remote server ( ssh -R ). Remote port forwarding might come in handy if you for example want to make your local web-server available on a port of a public server, so that someone can quickly check what your local web-server provides without having to deploy it somewhere publicly.

It should now be pretty easy to remember: Local and remote port forwarding always refers to where to relay the port to. The SSH command syntax uses the same easy to remember abbreviations: -L (forward to my local machine) and -R (forward to my remote machine).

Article series SSH tunnelling for fun and profit Local vs Remote Tunnel options AutoSSH SSH Config

TL;DR

Remote MySQL server (remote port 3306) to local machine on local port 5000:

ssh -L 5000:localhost:3306 cytopia@everythingcli.org

Local web-server (local port 80) to remote server on remote port 5000:

ssh -R 5000:localhost:80 cytopia@everythingcli.org

Local port forwarding

(Make a remote port available locally).

In this example we are going to make a remote MySQL Server (Port 3306) available on our local computer on port 5000.

Let’s start with the general syntax of local port forwarding:

ssh -L <LocalPort>:<RemoteHost>:<RemotePort> sshUser@remoteServer

Argument Explanation LocalPort The port on your local machine where the whole thing should be reachable. RemoteHost This specifies on which interface inside the remote server ( remoteServer ) the daemon is listening on. This can be either 127.0.0.1 , localhost , a specific IP address or even 0.0.0.0 which refers to all interfaces. If you are unsure, simply ssh into the remote machine and check all interfaces for port 3306 by issuing:

netstat -an | grep 3306 | grep LISTEN . RemotePort This is the actual port on the remote machine ( remoteServer ) you want to relay to your local machine. In our case (MySQL listens on 3306 by default) it is simply 3306 sshUser This is the SSH username you have on the remote server remoteServer The address (IP or hostname) by which your remote server is reachable via ssh

Now let’s simply forward our remote MySQL server to our local machine on port 5000 .

ssh -L 5000:localhost:3306 cytopia@everythingcli.org

That’s all the magic! You can now simply reach the remote database from your local machine with mysql --host=127.0.0.1 --port=5000 or any other client.

But wait… which local address does it listen on?

Yes, you are right! The complete syntax is:

ssh -L [<LocalAddress>]:<LocalPort>:<RemoteHost>:<RemotePort> sshUser@remoteServer

Argument Explanation LocalAddress The local address is an optional parameter. If you do not specify it, the remote port will be bound locally to all interfaces ( 0.0.0.0 ). So you can also only bind it locally to your 127.0.0.1 (on your local machine).

This is the full example:

ssh -L 127.0.0.1:5000:localhost:3306 cytopia@everythingcli.org

Remote port forwarding

(Make a local port available remotely).

In this example we are going to make our local web-server (Port 80) available on a remote server on Port 5000.

Let’s start with the general syntax of remote port forwarding:

ssh -R <RemotePort>:<LocalHost>:<LocalPort> sshUser@remoteServer

Argument Explanation RemotePort The port on your remote server ( remoteServer ) where the whole thing should be reachable. LocalHost This specifies on which interface inside your local computer the daemon is listening on. This can be either 127.0.0.1 , localhost , a specific IP address or even 0.0.0.0 which refers to all interfaces. If you are unsure, simply check all interfaces (on your local machine) for port 80 by issuing:

netstat -an | grep 80 | grep LISTEN . LocalPort This is the actual port on your local machine you want to relay to the remote server ( remoteServer ). In our case (The web-server listens on 80 by default) it is simply 80 sshUser This is the SSH username you have on the remote server remoteServer The address (IP or hostname) by which your remote server is reachable via ssh

Now let’s simply forward our local web-server to our remote machine on port 5000 .

ssh -R 5000:localhost:80 cytopia@everythingcli.org

That’s all the magic! You can now simply reach your local webserver via http://everythingcli.org:5000.

But wait… which remote address does it listen on?

Yes, you are right! The complete syntax is:

ssh -R [<RemoteAddress>]:<RemotePort>:<LocalHost>:<LocalPort> sshUser@remoteServer

Argument Explanation RemoteAddress The remote address is an optional parameter. If you do not specify it, the remote port will be bound remotely (on remoteServer ) to all interfaces ( 0.0.0.0 ). So you can also only bind it remotely to a specific interface.

This is the full example:

Assuming the IP address of everythingcli.org is 109.239.48.64 and you only want to bind it to this IP.

ssh -R 109.239.48.64:5000:localhost:80 cytopia@everythingcli.org

But wait… it doesn’t work

By default, the listening socket on the server will be bound to the loopback interface only. This may be overridden by specifying RemoteAddress . Specifying a RemoteAddress will only succeed if the server’s GatewayPorts option is enabled (on the remote server):

$ vim /etc/ssh/sshd_config GatewayPorts yes

Some more details

Ports below 1024

Every system user can allocate ports above and including 1024 (high ports). Ports below that require root privileges.

So If you want to relay any port to a port to for example 10, you must do that like so:

As you allocate a low port on your local machine, you must either do that as root (locally) or with sudo (locally):

sudo ssh -L 10:localhost:3306 cytopia@everythingcli.org

As you allocate a low port on the remote server, you will need to ssh into the machine as root:

ssh -R 10:localhost:80 root@everythingcli.org

_