SSH Tunnel: Local and Remote Port Forwarding

SSH Tunnel: Local and Remote Port Forwarding

About SSH

ssh stands for Secure Shell. It is a protocol used to securely connect to a remote server/system. ssh is secure in the sense that it transfers the data in encrypted form between the host and the client. For deep learning researchers, they usually use ssh to login their remote servers which have high-performance GPUs to train models. Besides its normal usage, it can be used to build tunnel to achieve local port forwarding and remote port forwarding (i.e. forwarding connections to port on machine to port on machine ). With the help of port forwarding, we can do something technically (e.g. passing firewall). In Linux, the ssh command is convenient to achieve these functions.

Local Port Forwarding

Local port forwarding is used to forward connections on a local port to another remote port on a different machine. Then all requests to the local port will be sent to the remote port by ssh tunnel.

Saying that we have a web server running in machine but it only allows requests from localhost(127.0.0.1). we want to visit this website on we own machine . If we type https://IP_of_machine_B:port in the browser URL bar, the connection will be refused of course. Then we need local port forwarding.

The syntax of ssh local port forwarding is :

ssh -fNTL local_port:remote_host:remote_port user@ssh_host

  • -f means let ssh to go to background just before command execution. So when type this command in local shell and type ENTER, it will return to the shell and we can do other things.

  • -N means do not execute a remote command. This is useful for just forwarding ports.

  • -T means disable pseudo-terminal allocation and it will save resource on both local and remote machine.

  • -L is the main parameter and it is used for Local port forwarding. Connections to local_port on localhost will be forwarded to remote_port on remote_host by ssh_host. The remote_host we want to request can be the same as ssh_host or not.

    For example, we have an application running in a host named app.com on port 8888, which is accessible only from the ssh_host server. Then we can request this application by ssh -fNTL 9999:app.com:8888 user@ssh_host. In this way, we type https://127.0.0.1:9999 on wer local browser URL bar and the connection will get forwarded to app.com:8888 by ssh_host and we’ll visit the application successfully.

E.g. Visit Remote Tensorboard

Tensorboard is an amazing tool to visualize the process of neural network model training. Training models in a remote server with high-performance GPUs but no GUI is familiar to DL researchers, and the tensorboard application will be deployed in the remote server, which cannot be visited by IP and port from our local browser (we don’t consider the tensorboard settings which may change its accessibility).

Suppose the remote server named gpu_server and tensorboard listen on port 6006. We can login the server as user yy. So the command we used is:

ssh -fNTL 16006:localhost:6006 yy@gpu_server

When we type https://127.0.0.1:16006 in the browser URL bar, the connection to our localhost on port 16006 will be forwarded to gpu_server:6006 by gpu_server. In this way, we establish a connection between our local browser and remote tensorboard service, but the remote tensorboard service only knows that the requests are from localhost (gpu_server) which has access permission.

Remote Port Forwarding

In contrast to local port forwarding, remote port forwarding aims to forward connections on remote server to our local machine. This is useful when we want to communicate with a server in a local-area network by a machine in the public network.

The syntax of ssh remote port forwarding is :

ssh -fNTR remote_port:localhost:local_port user@ssh_host

  • -R is the main parameter and it is used for Remote port forwarding. Connections to remote_port on ssh_host will be forwarded to localhost:local_port. Similar to local port forwarding, the localhost in the command can be replaced by other nearhost which can be connected from our localhost machine.

Note: When using remote port forwarding we need to add (or edit) GatewayPorts yes to /etc/ssh/sshd_config and restart the SSH daemon use sudo systemctl restart sshd on the ssh_host.

E.g. Intranet Penetration

Usually, we may have a server in wer workplace like school or company, and it can only be connected in local-area network because it doesn’t have a public network IP address. Even if we know the public IP address of wer workplace, we still can’t connect to the server by public_IP:port for NAT exists. we need to deploy an intranet penetration in advance when we want to connect to the server from home or on vacation.

Suppose:

ID location IP address login user name description
machine_A local area network 10.109.244.100 user_A target server
machine_B public network 39.97.183.218 user_B jump server
machine_C public network 103.121.208.230 user_C wer local machine
  • When we are in local-area network, login machine_A as user_A and type ssh -fNTR 2345:localhost:22 user_B@39.97.183.218 in terminal. This will establish a connect between machine_B and machine_A and connections to machine_B:2345 will be forwarded to machine_A:22.
  • In machine_B we should (or edit) GatewayPorts yes to /etc/ssh/sshd_config and restart the SSH daemon use sudo systemctl restart sshd.service. In machine_B run netstat -ntlp we will see port 2345 has been listened. But it will be 127.0.0.1:2345 which means only receive connections from localhost. If we run ssh user_A@39.97.183.218 -p 2345 in machine_C directly, we will receive a Connection refused message. But in machine_B, just run ssh user_A@localhost -p 2345 we can login machine_A successfully.
  • If we want to connect to machine_A directly:
    • Option 1: Run ssh -fNTL *:4567localhost:2345 localhost in machine_B. Then type netstat -ntlp we will see 0.0.0.0:4567 which means port 4567 can receive connections from anywhere. Then we can run ssh user_A@39.97.183.218 -p 4567 to login machine_A successfully.
    • Option 2: Change command in step 1 to ssh -fNTR *:2345:localhost:22 user_B@39.97.183.218. In machine_B we run netstat -ntlp and will see 0.0.0.0:2345 has been listening, which means we can run ssh user_A@39.97.183.218 -p 2345 to connect to machine_A directly.
  • SSH connection is unstable and will be closed if not be used for a long time. So we use sutossh to re-connect when the connection closed. The command we run in machine_A changed to sutossh -M 5566 -fNTR (*:)2345:localhost:22 user_B@39.97.183.218. -M means to specify a monitor port to check the connection status. When using autossh, we’d better run ssh-copy-id user_B@39.97.183.218 to copy the key to machine_B which makes sure we can login machine_B from machine_A without password.

Q.A.

Reference:

https://unix.stackexchange.com/questions/46235/how-does-reverse-ssh-tunneling-work

https://blog.jakuba.net/ssh-tunnel---local-remote-and-dynamic-port-forwarding/

Comments