SSH Tunnels Explained: Local, Remote, and Dynamic Port Forwarding Mechanics
Secure Shell (SSH) is ubiquitous across modern IT infrastructure as the default protocol for encrypted remote administration.
Beyond terminal emulation and shell execution, SSH incorporates a robust multiplexed transport layer capable of encapsulating arbitrary TCP connections inside an encrypted tunnel.
This capability, commonly referred to as SSH port forwarding or SSH tunneling, serves as a versatile Swiss Army knife for systems engineers, DevOps teams, and security specialists.
However, SSH tunneling is an architectural double-edged sword.
While it empowers engineers to securely reach isolated backend databases, bypass network address translation (NAT), and access management consoles across untrusted networks, it simultaneously provides adversaries and insider threats with an encrypted channel to bypass firewalls, exfiltrate data, and pivot across network segments (MITRE ATT&CK T1572: Protocol Tunneling and T1090: Proxy).
Understanding the low-level mechanics, packet flows, and configuration paradigms of SSH tunnels is critical for engineering secure remote access workflows and establishing defensive guardrails.
This article provides an in-depth technical analysis of local, remote, dynamic, and multi-hop SSH tunnels, their associated threat vectors, and the governance controls required to secure them.
Executive Context & Threat Modeling
From an architectural standpoint, an SSH tunnel operates by multiplexing application-layer data over an established SSH connection (RFC 4254).
The SSH client and SSH server negotiate symmetric encryption (such as AES-GCM or ChaCha20-Poly1305) and integrity checking over an asymmetric handshake (such as Ed25519 or ECDH key exchange).
Once the secure channel is established, logical forwarding channels can be opened on demand without re-authenticating each encapsulated stream.
Security leaders and infrastructure architects must balance operational utility against attack surface expansion:
Dimension
Operational Benefit
Security & Compliance Risk
Perimeter Traversal
Enables remote engineers to administer isolated internal databases without public IP exposure.
Bypasses stateful perimeter firewalls and Network Intrusion Prevention Systems (NIPS).
Data in Transit
Encrypts legacy, unencrypted protocols (e.g., HTTP, VNC, plain Redis) across public transit networks.
Conceals malicious data exfiltration and Command and Control (C2) traffic from Deep Packet Inspection (DPI).
Pivoting & Bastions
Provides single-entry jump host capabilities to enforce centralized logging and access control.
Allows compromised jump hosts to act as pivot points for lateral movement across internal subnets.
Compliance Alignment
Satisfies ISO/IEC 27001 Control A.8.20 (Network Security) by securing remote data channels.
Can violate segmentation policies if unauthorized egress tunnels bridge production and non-production environments.
Core Technical Mechanics: The Three Forwarding Modes
SSH port forwarding is categorized into three primary modes based on where the listener binds and the direction in which connections are dispatched: Local Forwarding (-L), Remote/Reverse Forwarding (-R), and Dynamic Forwarding (-D).
A. Local Port Forwarding (-L)
Local port forwarding configures the local SSH client to allocate a listening socket on the local host.
Whenever a local application connects to this local port, the SSH client encrypts the traffic, forwards it across the SSH tunnel to the SSH server, and instructs the SSH server to open a TCP connection to the specified target destination host and port.
Consider a PostgreSQL database running on 10.0.2.50:5432 inside an isolated private VPC subnet.
The engineer possesses SSH access to an edge bastion server at bastion.example.com.
# Bind local port 5433 to the remote private PostgreSQL database via bastionssh -N -f -L 5433:10.0.2.50:5432 devuser@bastion.example.com
Flags explained:
-N: Do not execute a remote command (only forward ports).
-f: Fork the SSH process into the background immediately before execution.
-L 5433:10.0.2.50:5432: Listens on 127.0.0.1:5433 locally and instructs bastion.example.com to establish a connection to 10.0.2.50:5432.
The local developer can now point their database client to localhost:5433, and all queries will be securely routed through the bastion.
B. Remote / Reverse Port Forwarding (-R)
Remote port forwarding reverses the listener placement.
The SSH client instructs the remote SSH server to allocate a listening socket on the remote machine.
When a process connects to this remote port on the server, the SSH server routes the connection back across the encrypted SSH channel to the SSH client, which then establishes a connection to the specified target host and port.
+--------------------------------------------------------------------------------+
| Reverse Forwarding Flow: ssh -R 9000:localhost:3000 user@cloud-vps.net |
| |
| 1. Remote user connects to cloud-vps.net:9000 |
| 2. SSH Server (cloud-vps) forwards stream back across tunnel -> Local Client |
| 3. Local SSH Client connects to localhost:3000 (Local Dev Web Server) |
+--------------------------------------------------------------------------------+
Concrete Use Case: Exposing a Local Development Server Behind NAT
An engineer developing a webhook consumer locally on port 3000 needs to receive external test webhooks from a third-party service.
The developer's workstation is behind a strict corporate NAT without public ingress.
# Instruct the public VPS to listen on port 8080 and forward traffic to local port 3000ssh -N -R 8080:127.0.0.1:3000 deploy@cloud-vps.example.com
By default, the OpenSSH server binds remote forwardings to the loopback interface (127.0.0.1) on the remote server for security.
To expose the port to external networks, the remote server's /etc/ssh/sshd_config must enable GatewayPorts:
# Enable external interfaces on remote port forwardingsGatewayPorts yes# Or to allow the client to specify the bind address:# GatewayPorts clientspecified
C. Dynamic Port Forwarding (-D) & SOCKS Proxying
While Local (-L) and Remote (-R) forwarding are point-to-point (forwarding a specific port to a pre-defined destination), Dynamic Port Forwarding transforms the SSH client into a local SOCKS (Socket Secure, RFC 1928) proxy server.
Instead of hardcoding a single destination IP and port, the application connects to the local SOCKS proxy and dynamically supplies the target hostname and destination port inside the SOCKS protocol handshake.
The SSH client forwards these dynamic requests through the encrypted tunnel, and the SSH server initiates the outbound connection to the desired target on behalf of the client.
Concrete Use Case: Browsing an Internal VPC Network
# Establish dynamic SOCKS5 proxy on local port 1080ssh -N -D 1080 admin@bastion.internal.net
Tools and browsers can now be configured to route all traffic through socks5://127.0.0.1:1080.
For CLI tools lacking native proxy support, proxychains-ng or curl --socks5-hostname can be utilized:
# Perform an HTTP request resolving internal DNS through the SSH bastioncurl --socks5-hostname 127.0.0.1:1080 https://internal-dashboard.corp.local
Using --socks5-hostname (SOCKS5 with remote DNS resolution) prevents DNS leakage by ensuring hostname resolution occurs on the remote bastion rather than the local client.
Multi-Hop Forwarding and Bastion Architectures
In multi-tier enterprise network designs, target systems are frequently nested behind multiple boundary firewalls and intermediate jump boxes.
Modern OpenSSH versions (7.3+) provide the -J (ProxyJump) directive, eliminating the historical need for complex netcat or ProxyCommand scripts.
To streamline daily operations, engineer declarative configurations in ~/.ssh/config:
# First-hop DMZ BastionHost dmz-bastion HostName bastion-public.example.com User jumpadmin IdentityFile ~/.ssh/id_ed25519 Port 22# Core Internal Bastion (Chained through DMZ)Host core-bastion HostName 10.0.1.10 User coreadmin ProxyJump dmz-bastion IdentityFile ~/.ssh/id_ed25519# Target Database Host with Automatic Local TunnelingHost production-db-tunnel HostName 10.100.4.50 User dbadmin ProxyJump core-bastion LocalForward 5432 127.0.0.1:5432 IdentityFile ~/.ssh/id_ed25519
Executing ssh production-db-tunnel will automatically authenticate across both jump hosts, establish the end-to-end channel, and bind local port 5432 directly to the production database's PostgreSQL listener.
Threat Analysis: The Attack Surface of SSH Tunneling
Security architects must evaluate how attackers exploit SSH tunneling mechanisms within target environments.
1. Covert Egress & Data Exfiltration
Adversaries with compromised endpoints on an internal network can establish outbound reverse SSH tunnels (ssh -R) to external attacker-controlled infrastructure.
Because egress firewalls frequently permit outbound TCP port 22 or outbound HTTPS (port 443, to which an external SSH server can be configured to listen), this creates a persistent, bidirectional interactive shell bypassing stateful boundary filters.
2. Lateral Movement & Network Pivoting
When an attacker gains credentials to a standard jump host, dynamic port forwarding (ssh -D) allows the attacker to route vulnerability scanners (e.g., Nmap, Nikto) directly against internal subnets that are completely unreachable from the public internet.
3. Loopback Hijacking
When a developer creates a local tunnel on a shared multi-user server (e.g., a shared compute cluster), binding to 0.0.0.0 or failing to restrict local bind addresses allows any other unprivileged local user on that server to connect to the forwarded port and access the remote resource without authenticating.
Actionable Hardening & Defensive Governance
Securing SSH infrastructure requires implementing defense-in-depth controls at the host, network, and policy levels.
Host-Level SSH Daemon Hardening (sshd_config)
System administrators should restrict tunneling capabilities on production servers and bastion hosts according to the principle of least privilege.
# /etc/ssh/sshd_config Hardening Directives# Disable TCP port forwarding completely on high-security backend serversAllowTcpForwarding no# On Bastion hosts where forwarding is required, restrict binding to loopback onlyGatewayPorts no# Prevent remote execution of shell commands when users only require tunnel accessMatch Group tunnel-only-users AllowTcpForwarding yes X11Forwarding no AllowAgentForwarding no PermitTTY no ForceCommand /usr/sbin/nologin # Explicitly restrict destinations reachable via port forwarding PermitOpen 10.0.2.50:5432 10.0.2.60:3306
Directives Breakdown:
PermitTTY no & ForceCommand /usr/sbin/nologin: Blocks the user from obtaining an interactive shell while allowing port forwarding to function.
PermitOpen host:port: Enforces strict destination allowlisting. The SSH server will reject any -L or -D request to targets not explicitly enumerated in this list.
AllowAgentForwarding no: Prevents malicious servers or attackers on intermediate jump boxes from hijacking the client's local SSH agent keys.
Network & Detection Controls
Egress Filtering (NIST SP 800-41):
Restrict outbound connections on port 22 from internal workloads to strictly authorized corporate bastion IPs.
Behavioral Protocol Inspection:
Utilize Zeek (formerly Bro) and Suricata to perform SSH session fingerprinting (e.g., HASSH signatures) and analyze session byte duration and flow heuristics to detect long-lived interactive tunneling sessions.
Short-Lived SSH Certificates:
Replace static SSH public keys with OpenSSH Certificate Authorities (CA) issued via Identity Providers (e.g., HashiCorp Vault, Teleport, or Smallstep) with embedded validity windows limited to several hours.
Summary
SSH tunneling provides an exceptionally capable and encrypted mechanism for local, remote, and dynamic network routing.
However, its dual nature as both an administrative asset and an adversary exfiltration pathway requires deliberate engineering controls.
By implementing strict sshd_config configurations (PermitOpen, disabled TTYs, disabled agent forwarding), deploying short-lived SSH certificates, and monitoring encrypted session durations, organizations can leverage the operational agility of SSH tunnels while maintaining zero-trust segmentation and compliance integrity.