Port forwarding (or tunnelling) is a method to forward one network traffic to another. We will introduce how to forward ports using SSH tunnel in this post.
A simple example
Let’s start with a simple and useful example: we want to forward local port 8080 to server:port. We can easily do this by using ssh like this:
ssh -L 8080:server:port username@ssh_server
ssh_server is the sshd server that we can use. Then connection to 127.0.0.1:8080 will be automatically forwarded to server:port.
Port forwarding (or tunnelling) is a method to forward one network traffic to another. For example, there are three servers s1, s2, s3 and one client c0. There is a ssh tunnel between s1 and s2. When c0 sends a packet to s1′s port p1, the packet can be forwarded through the traffic through the tunnel between s1 and s2 and will arrives s3′s port p3. The packet of the opposite direction follows the opposite way. That is:
c0:p0 <--> s1:p1~s1:p1' <==> s2:p2~s2:p2' <--> s3:p3
From c0′s view, it connect to s1′s port p1, but actually, the service is provided through s3′s port p3. If c0 is the user or the client of the service, then the ssh security tunnel will exist between s1 and s2. This will be very useful. For example, we can use this method to secure the insecure network such as SMTP, HTTP, POP3, etc. If c0 and s1 are in the secure local network area and s2 and s3 are in another secure local network area, while the two local network area are connected through the insecure internet. The connection between the client c0 and the application sever s3 is insecure. Then we can create the ssh tunnel between s1 and s2. The tunnel is encrypted and secure. So s3′s service can be provided to client c0 in a secure way as the traffic in the insecure network is encrypted. This is a method to secure an “insecure” connection, of course, with the cost of encryption and decryption.
We do not need to have exactly four server/clients. c0 and s1 can be the same server and c0 can just connect to the localhost which is itself. It the same for s2 and s3. So there may be two, three or four server/clients in this system. Only one server will also work, but it’s actually useless. An usual way of using this is that c0 and s1 is the same server. After the tunnel has been set up, c0 will use the forwarding port on localhost itself .
Either s1 or s2 can be the sshd server for the ssh tunnel. So there are two kinds of port forwarding: Local forwarding and Remote forwarding.
Another name of local forwarding is outgoing tunnel. s2 is the sshd server of this ssh tunnel, while s1 is the ssh client. From the view of s1, the tunnel is outgong and it is listening on the local port. So it is called “local” forwarding or “outgoing” tunnel.
We also use the previous example that we want to port forwards port p1 of s1 to port p3 of s3. The method is using this command on s1:
ssh -L p1:s3:p3 username@s2
sshd usually listens on port 22 which is p2 here. If sshd’s service port is not the normal one 22, then add the -p p2 argument to ssh. When a packet is received on port p1 by s1, s1 sends this packet through the tunnel between s2 and itself, then s2 will send this packet to s3:p3.
Or incoming tunnel. In this case, s1 is the sshd server and s2 is the ssh client. From the ssh client s2′s view, the remote side (s1) listens on the port and forwarding packet through the tunnel. The ssh client gets incoming packet through the tunnel.
The method is using this command on s2:
ssh -R p1:s3:p3 username@s1
The packet to s1:p1 will be forwarded to s3:p3 through the tunnel as the local forwarding. This is useful especially when s1 and s3 are behind a firewall that does not allow opening any port. This method provides a way to remote control a machine behind the firewall. We can also see that even with a strict firewall, the protected local area network can also be controlled remotely.
ssh is a user space application, and the performance of port forwarding is not as good as some other approach such as iptables. But ssh tunnel is easy to set up even without root privilege granted to the user, which make it a very convenient tool on Linux/Unix systems.
GatewayPorts should be “yes” in /etc/ssh/sshd_config on sshd server if remote forwarding is enabled for machine c0.
Specifies whether remote hosts are allowed to connect to ports forwarded for the client. By default, sshd binds remote port forwardings to the loopback address. This prevents other remote hosts from connecting to forwarded ports. GatewayPorts can be used to specify that sshd should allow remote port forwardings to bind to non-loopback addresses, thus allowing other hosts to connect. The argument may be “no to force remote port forwardings to be available to the local host only, “yes to force remote port forwardings to bind to the wildcard address, or “clientspecified to allow the client to select the address to which the forwarding is bound. The default is “no”.
“Dynamic” port forwarding
SSH can be use for local “dynamic” application-level port forwarding. ssh will act as a SOCKS server. Please refer to [[proxy-using-ssh-tunnel]] for more details.