SSH Port Forwarding ⤳ aka SSH Tunneling.

SSH port forwarding (SSH Tunneling) is a method for safely transmitting data over an encrypted SSH; tunneling application ports from a connection between a local and distant server or vice versa.

SSH Port Forwarding ⤳ aka SSH Tunneling.
Photo by yannick Coffi see +< @ yannickcoffi @ PRINTS

What Is SSH Tunneling?

SSH tunneling is a powerful feature widely used by system administrators and developers to securely access services across different networks or to bypass restrictive firewall rules.

At a high level, SSH tunneling allows you to forward any TCP/IP port through an encrypted SSH connection. Instead of application traffic traveling directly over the network, it is encapsulated inside the SSH session. This ensures that the data remains confidential and protected from eavesdropping, interception, or manipulation while in transit.

Because the traffic is encrypted end-to-end, SSH tunnels are commonly used to:

  • Access internal services from untrusted networks
  • Secure legacy or unencrypted protocols
  • Reach restricted resources behind firewalls or NAT devices
  • Safely manage remote systems over insecure networks

⚠️ Security Considerations

While SSH tunneling is a legitimate and essential administrative tool, it can also be misused. Attackers and malware may abuse SSH tunnels to:

  • Create covert backdoors from the Internet into internal networks
  • Exfiltrate data through encrypted channels that evade inspection
  • Obscure their activity by routing attacks through multiple intermediate hosts that allow unrestricted tunneling

For this reason, SSH tunneling should be carefully monitored, controlled, and restricted to trusted users and well-defined use cases, especially in enterprise or production environments.


Let Us Explore: How SSH Port Forwarding Works

SSH tunneling enables secure port forwarding, which can be implemented in three main ways: local, remote, and dynamic port forwarding. Each method serves different use cases depending on where the traffic originates and where it needs to go.

  1. Local port forwarding: Redirects traffic from a local port on the client machine to a specified port on a remote server via an SSH connection.
  2. Remote port forwarding: Redirects traffic from a port on the remote server to a specified port on the client machine.
  3. Dynamic port forwarding: Creates a SOCKS proxy on the client machine, enabling the forwarding of traffic from various applications through the SSH connection.


Case Study: Secure Application Access

Here, in our SNUBmonkey VM lab environment, we host multiple application projects, each running on its own local service port. These applications are isolated within their respective development environments and are not directly exposed to external networks for security reasons.

The challenge is to provide secure, controlled access to these application ports for testing, collaboration, or remote administration—without opening firewall rules or publicly exposing the services.

To address this, we use SSH tunneling as a secure transport mechanism. By forwarding specific local application ports through an encrypted SSH connection, authorized users can access these services remotely as if they were running on their own machines. All traffic between the client and the VM is encapsulated within SSH, ensuring confidentiality and integrity.

Objectives of This Lab

  • Securely expose multiple local application ports without public network access
  • Avoid modifying firewall or NAT configurations
  • Maintain strict access control using SSH authentication
  • Provide a reproducible and auditable access method for developers and administrators


Clarifying Some Key Concepts

Let's take a moment to clarify a few fundamental notions. If you’re already familiar with them, feel free to skip this section.

What is a localhost?

The term "localhost" refers to the computer or device you are currently using. It is commonly associated with the loopback IP address 127.0.0.1. This address allows your computer to send network traffic to itself.

Why it's useful:

  • Testing network applications locally without exposing them to the network
  • Accessing services that are running only on your own machine, such as a local web server or database

Think of it as a "private network within your own computer."

What is a Bind-address?

A bind address specifies the network interface or IP address that an application listens on for incoming connections. Essentially, it tells the application: "Listen for traffic on this IP and port combination."

Key points:

  • When a socket is associated with an IP address and a port number, it is said to be bound to that address
  • The action of assigning a port number to a socket is called binding
  • Only applications bound to an address can receive network data sent to that address

This concept is crucial when configuring servers or SSH tunnels, as it determines which clients can reach your service.


What is a Proxy Server?

A proxy server acts as an intermediary between a client and a destination server. It forwards requests from the client to the destination and can return responses back.

Common uses:

  • Caching: Improve performance by storing frequently accessed content
  • Security/Filtering: Control access to certain resources or block malicious traffic
  • Anonymity: Hide the client's real IP address from the destination server

In SSH tunneling, a dynamic port forward effectively creates a local SOCKS proxy, allowing multiple applications to route traffic securely through an SSH tunnel.


1. Local Port Forwarding

Local port forwarding is the most commonly used type of SSH tunneling. It allows you to access a service on a remote machine that is otherwise not directly accessible from your local device—all over a secure, encrypted connection.

Typical Use Cases

Local port forwarding is useful in scenarios such as:

  • Accessing a database (MySQL, MariaDB, Redis, Postgres, etc.) from your local machine
  • Accessing a container or VM port without exposing it on the server’s public interface
  • Using a browser to access a web application that is restricted to a private network

How It Works

Consider a remote application that listens on localhost of the remote server (127.0.0.1:3914).
From your local machine, there is no direct way to connect to this port because it is not publicly exposed.

This is where SSH local port forwarding comes into play: you can forward a local port to the remote service over SSH, making it accessible on your machine as if it were local.

Example Command

Using OpenSSH, local port forwarding is initiated with the -L flag. The -N flag prevents starting an interactive shell session, which is useful if you only want to forward ports.

$ ssh -N -L source_port:forward_to_host:destination_port via_host

$ ssh -N -L 3914:localhost:3914 [REMOTE_USER]@[REMOTE-SERVER_IP]
([REMOTE_USER]@[REMOTE-SERVER_IP]) Password:


In the above example, the SSH command opens a connection to the jump server at 192.168.1.xxx and forwards traffic from a local port on your machine to port 3914 on the remote server.

  • The local port does not need to match the remote port. For example, you could forward local port 5000 to remote port 3914.
  • Once the tunnel is established, visiting http://localhost:5000 in your browser will securely connect to the remote service running on 127.0.0.1:3914 on the jump server.

Forwarding Multiple Ports

You can forward multiple ports in a single SSH session by specifying multiple -L flags in the same command:

$ ssh -N -L 4562:localhost:3305 -N -L 3286:127.0.0.1:6512 [REMOTE_USER]@[REMOTE-SERVER_IP]
([REMOTE_USER]@[REMOTE-SERVER_IP]) Password:

Securing Access to Remote Services

By default, when you forward a port using SSH, the local port on your machine may be accessible to other machines on the same network. This can be a security risk if untrusted devices exist on the network.

To restrict access so that only programs running on your own host can connect to the forwarded port, you can specify a bind address when creating the SSH tunnel.

Example: Binding to Localhost

$ ssh -N -L 127.0.0.1:3914:localhost:3914 [REMOTE_USER]@[REMOTE-SERVER_IP]
([REMOTE_USER]@[REMOTE-SERVER_IP]) Password:


2. Remote Port Forwarding (Reverse tunneling)

Remote port forwarding, also called reverse SSH tunneling, allows you to make a local service accessible to a remote server.

The term "reverse" refers to the flipping of the usual data direction:

  • Normally, SSH connections originate from your local machine to a remote server
  • With reverse tunneling, the remote server can initiate a connection back to your local machine

This is particularly useful when your local machine is behind NAT, firewalls, or other network restrictions, preventing direct inbound connections.

How It Works

  • You run an SSH command on your local machine using the -R flag
  • The remote server opens a listening port that forwards traffic through the SSH tunnel to your local service

Example Command

Suppose you have a web service running on your local machine at localhost:2399 and you want it accessible from a remote server:

$ ssh -N -R source_port:forward_to_host:destination_port via_host

$ ssh -N -R 2393:localhost:2399 [REMOTE_USER]@[REMOTE-SERVER_IP]
([REMOTE_USER]@[REMOTE-SERVER_IP]) Password:


In this example, SSH establishes a connection to [REMOTE-SERVER_IP].

  • The -R flag instructs SSH to listen on port 2393 on the remote server
  • Any process on [REMOTE-SERVER_IP] that connects to port 2393 will have its traffic forwarded through the SSH tunnel
  • That traffic is then delivered to your local machine at localhost:2399

In effect, a service running locally on port 2399 becomes accessible from the remote server via port 2393, with all communication securely encapsulated inside the SSH connection.

This mechanism allows remote systems to reach services that are otherwise unreachable due to NAT, firewall rules, or private network boundaries.

Remember, you don’t have to use localhost; any valid hostname or IP can be the tunnel’s destination. This enables remote access to internal services, such as private web servers.

Caution:
Although useful for legitimate tasks like remote testing, reverse tunnels can be abused to expose internal applications. Always restrict and monitor their use.

Controlling Remote Port Access with GatewayPorts

By default, OpenSSH only allows connections to remote forwarded ports from the server itself. The GatewayPorts option in the SSH server configuration file (/etc/ssh/sshd_config) controls whether external hosts can connect to these ports.

Available Options

  • GatewayPorts no (default)
    Only the server host can connect to the forwarded port. External connections are blocked.
  • GatewayPorts yes
    Any host can connect to the forwarded port. If the server is public, this exposes the port to the Internet.
  • GatewayPorts clientspecified
    The client can choose which IP address the remote port listens on.

Example:

$ ssh -R 15.152.66.244:8080:localhost:80 host232.whatever.com
  • Only connections from 15.152.66.244 to port 8080 on the remote server are allowed
  • Traffic is securely forwarded to your local localhost:80

Security Note:

  • GatewayPorts yes can expose services to the public and is generally risky
  • GatewayPorts clientspecified is safer, allowing fine-grained control over which hosts can connect


3. Dynamic port forwarding

Dynamic port forwarding, allows you to create a secure, general-purpose tunnel between your machine and a remote SSH server. Unlike local or remote port forwarding, which forward specific ports, dynamic forwarding can redirect traffic from any application or port through the SSH connection.

Effectively, this turns the remote SSH server into a SOCKS proxy, making it harder for third parties to intercept or track your activities.

Common Use Cases

  • Accessing websites or services that are blocked or restricted
  • Bypassing network censorship
  • Protecting your privacy when browsing or using network applications

How to Use

In OpenSSH, dynamic port forwarding is initiated using the -D flag, followed by a local port number that will act as the SOCKS proxy:

$ ssh -D [local_port] [REMOTE_USER]@[REMOTE-SERVER_IP]

$ ssh -D 45337 -C -N -f -p 1234 [REMOTE_USER]@[REMOTE-SERVER_IP]
([REMOTE_USER]@[REMOTE-SERVER_IP]) Password:

The options used are as follows:

  • -D 45337
    Allocates a local dynamic port (45337) for application-level forwarding. This acts as a SOCKS proxy, optionally bound to a specific address.
  • -C (optional)
    Compresses all data (stdin, stdout, stderr, and forwarded connections) using the same algorithm as gzip. Useful for slow connections; may slightly reduce speed on fast networks.
  • -N
    Tells SSH not to execute a remote command, keeping the session dedicated to forwarding.
  • -f (optional)
    Sends SSH to the background, allowing the tunnel to run silently.
  • -p 1234
    Specifies the SSH server port if it is not the default 22.
  • [REMOTE_USER]@[REMOTE-SERVER_IP]
    Your SSH login credentials.

Dynamic port forwarding uses the SOCKS protocol, with SSH acting as a local SOCKS proxy that routes traffic securely through the tunnel. The client must be SOCKS-aware—for example, a browser configured to use the proxy.

Configuring your Browser to Use a Proxy Server


Now that the SSH SOCKS tunnel has opened, the last step is to configure your preferred browser.

Chrome# on macOS.

The steps below might but different on Windows or Linux.

  1. In the upper left-hand, click on Chrome's menu.
  2. Settings...  ⌘,
  3. Scroll down to the System menu section and click on Open your computer's proxy settings .
  4. MacOS System settings will pop up; right on the Proxies tab.
    1. Select and enable SOCKS proxy.
    2. Enter 127.0.0.1 or localhost in the Server field and whatever port number you have previously chosen in the Port field.
    3. Click on the OK button to save the settings.

At this point, your Chrome should be configured and you can browse the Internet through the SSH tunnel.


Check for LISTEN| ESTABLISHED ports

Let's inspect for open TCP ports that are actively listening like PROS.

Run the below command on the host where you initiated the proxy.

$ lsof -nP -i4TCP:45337 | grep LISTEN

OUTPUT

ssh     29300 xxxxx    6u  IPv4 0xb89bd28ef6dd03ff      0t0  TCP 127.0.0.1:45337 (LISTEN)


As you can see the SOCKET is waiting to be connected. (LISTEN)
A listening port refers to a port on a computer that is actively awaiting inbound requests, ready to receive incoming data or connections on that specific port number.

Again, we will run the below this time on the SERVER side.

$ lsof -nP -i4TCP | grep 192.168.1.xxx

OUTPUT

sshd    26073 xxxxx    4u  IPv4 0x1e84b24b17ed2aad      0t0  TCP 192.168.1.xxx:22->192.168.1.xxx:52025 (ESTABLISHED)
sshd    26073 xxxxx    5u  IPv4 0x1e84b24b17ed2aad      0t0  TCP 192.168.1.xxx:22->192.168.1.xxx:52025 (ESTABLISHED)


As you can see the SOCKET is connected. (ESTABLISHED)
An established port refers to a port on a computer that is actively receiving and processing data from another computer.


Security Concerns of Port Forwarding


While port forwarding can be a useful technique for accessing remote devices and services, if not implemented correctly, it can pose security risks.

The following are the primary safety concerns with port forwarding:

  1. Exposure of Services: Port forwarding exposes internal services to the internet, potentially allowing unauthorized access to those services if not properly secured.
  2. Target for Attacks: Open ports created by port forwarding can become targets for attackers who may attempt to exploit vulnerabilities in the exposed services.
  3. Misconfiguration: Incorrectly configured port forwarding rules may inadvertently expose sensitive data or services, leading to data breaches or unauthorized access.
  4. Increased Attack Surface: Port forwarding increases the attack surface of a network by providing more entry points for potential attackers.

It's essential to carefully consider the security implications and follow best practices when implementing port forwarding to mitigate these risks.

There are a few steps you can take to mitigate the security risks associated with port forwarding. These include:

  1. Limit Exposure: Only forward ports that are absolutely necessary for your intended use. Close any unused ports to reduce the attack surface.
  2. Implement Access Controls: Restrict access to forwarded ports by using firewall rules or access control lists (ACLs) to allow only authorized IP addresses or networks to connect.
  3. Regularly Update Software: Keep all software and services running on forwarded ports up to date with the latest security patches to address known vulnerabilities.
  4. Enable Logging and Monitoring: Enable logging and monitoring for forwarded ports to detect and respond to suspicious activities or unauthorized access attempts.
  5. Employ Intrusion Detection/Prevention Systems (IDS/IPS): Use IDS/IPS solutions to monitor network traffic for signs of malicious activity and block or alert on suspicious behavior.
  6. Implement Two-Factor Authentication (2FA): Require two-factor authentication for accessing sensitive services or systems exposed through port forwarding to add an extra layer of security.

By following these steps, you can significantly reduce the security risks associated with port forwarding and better protect your network and systems.


Wrapping up this tutorial, I want to express my sincere gratitude to each participant for their invaluable contributions. Learning is a collaborative journey, and I encourage everyone to stay curious and continue asking questions. This tutorial marks just the beginning of our quest for deeper understanding.

Thank you all once again, and best wishes on your learning journey ahead!

Keep Us Caffeinated  ⦿ ⦿
Icon Join our 33K+ readers Spotify Logo