SSH - Port Forwarding: Local and Reverse Tunnels
Greetings!

Today we will look at port forwarding through SSH 🔐: how to use local and reverse tunnels to organize access to local and remote services.

Local Port Forwarding

For example, we need to connect from a local machine to a database💽 that is available only on the localhost interface of a remote server🖥.

You can open an SSH tunnel with this command:

BASH
ssh -q -f -N -L 127.0.0.1:5432:localhost:5432 ivan@test.r4ven.me
Click to expand and view more

Where:

First comes address:port of the local host, then address:port of the remote one.

This command will open the tunnel in the background and keep it running permanently. Now you can connect to the database at 127 0.0.1:5432

If this is your goal, the task is solved👌.

But what if you need to open the tunnel only for the duration of some operations? For example, when configuring automation using shell scripts📝. Obviously, in this case, after the work is finished, the tunnel must be closed🔒.

Unfortunately, SSH has no built-in functionality for providing the PID of the background process😢.

Therefore, you can close the tunnel in a crude way, through pkill 🎯, passing the full tunnel opening command as an argument😒.

Example:

BASH
pkill -f "ssh -q -f -N -L 127.0.0.1:5432:localhost:5432 ivan@test.r4ven.me"

# or

pgrep -f "ssh -q -f -N -L 127.0.0.1:5432:localhost:5432 ivan@test.r4ven.me" | xargs kill
Click to expand and view more

This method works, but it is not exactly elegant. And it is unsafe: if you make a mistake in the argument, you can accidentally kill another running process🤷♂

The search for an alternative solution took quite some time⏳

And here is an example:

BASH
ssh -q -f -L 127.0.0.1:5432:localhost:5432 test.r4ven.me sleep 60
Click to expand and view more

The point is that we open the tunnel for 60 seconds. During this time, you need to start the command you need🐧.

Even if your application command takes more than a minute to run, the connection will not be interrupted UNTIL it completes😌. In other words, the tunnel will close correctly and automatically👍.

Below is the command variant I used in one of my scripts:

BASH
ssh -q -f -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ExitOnForwardFailure=yes -L 127.0.0.1:5432:localhost:5432 test.r4ven.me -p 2222 -l ivan -i ~/.ssh/id_ed25519_test sleep 60
Click to expand and view more

Additional options:

Maybe it will be useful to someone for their shell 🐚 scripts🙃.

Reverse Port Forwarding

Now let’s talk about reverse tunnels🌐.

For example, you need to direct data from port 4443 of a remote machine to port 5001 of a local one:

BASH
ssh -q -f -N -R 127.0.0.1:4443:localhost:5001 ivan@test.r4ven.me
Click to expand and view more

Let me remind you:

First comes address:port of the remote host, then address:port of the local one.

If needed, you can close the connection with this crude command:

BASH
pkill -ef 'ssh -q -f -N -R 127.0.0.1:4443:localhost:5001 ivan@test.r4ven.me'
Click to expand and view more

As you noticed, we forwarded a port on the remote machine that waits for connections on the local interface. To forward a non-localhost interface, specify it explicitly. Or forward all interfaces:

BASH
ssh -q -f -N -R 0.0.0.0:4443:localhost:5001 ivan@test.r4ven.me
Click to expand and view more

Most likely, if you run the following on the remote machine:

BASH
ss -tln | grep 4443
Click to expand and view more

You will see:

BASH
Local Address:Port
127.0.0.1:4443
Click to expand and view more

The remote port still listens on the local interface🤔

The reason is secure shell, which would not be secure if it did not have secure default parameters😎.

For security reasons, reverse port forwarding on a non-local interface is disabled. The GatewayPorts parameter in the SSH config is responsible for this🔒.

To allow reverse forwarding, open the sshd config:

BASH
nvim /etc/ssh/sshd_config
Click to expand and view more

And set the GatewayPorts parameter to yes.

After that, restart the sshd daemon:

BASH
sshd -t

systemctl restart sshd
Click to expand and view more

Reopen the tunnel:

BASH
pkill -ef 'ssh -q -f -N -R 0.0.0.0:4443:localhost:5001 ivan@test.r4ven.me'

ssh -q -f -N -R 0.0.0.0:4443:localhost:5001 ivan@test.r4ven.me
Click to expand and view more

And check the port on the remote machine again:

BASH
ss -tln | grep 4443
Click to expand and view more

Everything is as it should be:

BASH
Local Address:Port
0.0.0.0:4443
Click to expand and view more

Now, when connecting from any client, you will be forwarded to your local system:

BASH
nc -zv test.r4ven.me 4443

curl test.r4ven.me:4443
Click to expand and view more

Have a good day!👋

Copyright Notice

Author: Ivan Cherniy

Link: https://r4ven.me/en/networking/ssh-probros-portov-pryamye-i-obratnye-tunneli/

License: CC BY-NC-SA 4.0

Blog materials may be used with attribution to the author and source, for non-commercial purposes, and under the same license.

Start searching

Enter keywords to search articles

↑↓
ESC
⌘K Shortcut