Demystifying SSH Port Forwarding: Local, Remote, and Dynamic Tunnels Explained
Learn local, remote, and dynamic SSH port forwarding with practical commands for databases, web apps, and SOCKS proxies.
Demystifying SSH Port Forwarding: Local, Remote, and Dynamic Tunnels Explained
SSH port forwarding lets you reach a network service through an encrypted SSH connection instead of exposing that service directly. You will usually use it when a database, dashboard, or development server is reachable from an SSH host but not from your laptop.
The three common forms are local forwarding, remote forwarding, and dynamic forwarding. They use similar syntax, but the listening port sits in a different place.
What SSH Port Forwarding Does
SSH port forwarding, also known as SSH tunneling, redirects traffic from one host and port to another host and port through your SSH session. The destination is resolved from the side that makes the final connection. For local forwarding, the SSH server connects to the target. For remote forwarding, your SSH client connects to the target.
This offers several advantages:
- Security: Encrypts traffic that would otherwise be unencrypted between your client and the target service.
- Access Control: Allows access to services running on private networks or behind firewalls that are not directly accessible from your current location.
- Bridging Networks: Connects different network segments securely.
Local Port Forwarding (-L)
Local port forwarding is the most common type. It allows you to forward connections from a port on your local machine to a port on a remote machine, via an SSH server. Essentially, you make a service running on the remote network appear as if it's running on your local machine.
How it works:
- You start an SSH client on your local machine.
- You specify a local port (
local_port) that SSH will listen on. - Any connection made to
local_porton your local machine is forwarded through the SSH connection to theremote_hostandremote_port.
Syntax:
ssh -L [local_bind_address:]local_port:remote_host:remote_port [user@]ssh_server_host
local_bind_address: Optional address on your local machine to bind. If omitted, OpenSSH normally binds to loopback addresses unless your client configuration says otherwise.local_port: The port on your local machine that SSH will listen on.remote_host: The hostname or IP address of the target machine that the SSH server will connect to.remote_port: The port on theremote_hostthat the traffic will be directed to.user@ssh_server_host: Your username and the hostname/IP address of the SSH server you are connecting to.
Practical Use Case: Accessing a database server running on a remote server's private IP address.
Imagine a database server (e.g., PostgreSQL on 192.168.1.100:5432) that's only accessible from your company's internal network. You can use local port forwarding to access it from your laptop at home:
ssh -L 5433:192.168.1.100:5432 your_user@your_ssh_server.com
- This command connects you to
your_ssh_server.com. - It opens port
5433on your local machine (localhostby default). - Any connection to
localhost:5433will be forwarded throughyour_ssh_server.comto192.168.1.100:5432.
Now, you can configure your local database client to connect to localhost:5433, and the traffic will be securely tunneled to the remote database server.
Tip: Use ssh -N to create a tunnel without executing a remote command. This is useful for background tunnels.
ssh -N -L 5433:192.168.1.100:5432 your_user@your_ssh_server.com
Remote Port Forwarding (-R)
Remote port forwarding allows you to forward connections from a port on the remote SSH server to a port on your local machine or another machine accessible from your local machine. This is useful for making a service running on your local machine accessible to the remote server or its network.
How it works:
- You start an SSH client on your local machine.
- You specify a remote port (
remote_port) on the SSH server that SSH will listen on. - Any connection made to
remote_porton the SSH server is forwarded through the SSH connection back to your local machine and then to a specifieddestination_hostanddestination_port.
Syntax:
ssh -R [remote_bind_address:]remote_port:destination_host:destination_port [user@]ssh_server_host
remote_bind_address: (Optional) The address on the SSH server to bind the listening port to. Defaults tolocalhost(meaning only the SSH server itself can connect to this port). Use0.0.0.0or*to allow other machines on the remote network to connect.remote_port: The port on the SSH server that SSH will listen on.destination_host: The hostname or IP address of the target machine that your SSH client will connect to (oftenlocalhostif the service is on your local machine).destination_port: The port on thedestination_hostthat the traffic will be directed to.user@ssh_server_host: Your username and the hostname/IP address of the SSH server you are connecting to.
Practical Use Case: Exposing a local web server to a remote network.
Suppose you are developing a web application on your laptop and want to demonstrate it to a colleague who only has access to your company's internal network, and you have an SSH server (your_ssh_server.com) accessible from that network.
On your laptop, you would run:
ssh -R 8080:localhost:3000 your_user@your_ssh_server.com
- This command connects you to
your_ssh_server.com. - It tells
your_ssh_server.comto listen on port8080. - Any connection to
your_ssh_server.com:8080will be forwarded back through the SSH tunnel to your laptop (localhost) on port3000(where your web server is running).
Now, your colleague can access your web application by navigating to http://your_ssh_server.com:8080 in their browser. The traffic goes from their browser to the SSH server, through the tunnel to your laptop, and then to your web server.
Warning: In typical OpenSSH configurations, the remote_port is reachable only from the SSH server itself. To allow other machines on the remote network to access the forwarded port, explicitly set remote_bind_address to 0.0.0.0 or * and make sure the SSH server permits it with a GatewayPorts setting such as clientspecified or yes.
ssh -R 0.0.0.0:8080:localhost:3000 your_user@your_ssh_server.com
Dynamic Port Forwarding (-D)
Dynamic port forwarding creates a SOCKS proxy on your local machine. This is arguably the most flexible type, as it allows you to tunnel any application that supports SOCKS proxies through your SSH connection. Instead of forwarding a specific port, SSH listens on a local port and acts as a SOCKS proxy server.
How it works:
- You start an SSH client on your local machine.
- You specify a local port (
local_port) that SSH will listen on as a SOCKS proxy. - You configure your applications (web browser, etc.) to use
localhost:local_portas their SOCKS proxy. - When an application makes a request through this proxy, SSH forwards the traffic to the SSH server, which then makes the connection to the ultimate destination on behalf of your application.
Syntax:
ssh -D [local_bind_address:]local_port [user@]ssh_server_host
local_bind_address: (Optional) The address on your local machine to bind the listening SOCKS proxy port to. Defaults tolocalhost.local_port: The port on your local machine that SSH will listen on as a SOCKS proxy.user@ssh_server_host: Your username and the hostname/IP address of the SSH server you are connecting to.
Practical Use Case: Securely browsing the web from a public Wi-Fi.
When connected to an untrusted public Wi-Fi network, your traffic is vulnerable. You can use dynamic port forwarding to tunnel all your web browsing traffic through an encrypted SSH connection to a trusted server.
On your laptop, run:
ssh -D 1080 your_user@your_trusted_server.com
- This command connects you to
your_trusted_server.com. - It opens port
1080on your local machine, acting as a SOCKS proxy.
Next, configure your web browser or other application to use a SOCKS proxy at localhost on port 1080. If the application has a SOCKS5 remote DNS option, use it when you do not want DNS lookups to happen on your local network.
Your browser traffic is sent to your SSH server, which then connects to the destination site. HTTPS still matters; the SSH tunnel protects the path to your SSH server, not every hop after it.
Tip: You can combine -D with -C for compression, which can be beneficial on slower network links.
ssh -C -D 1080 your_user@your_trusted_server.com
Advanced Considerations and Best Practices
- SSH Server Configuration (
sshd_config): Some forwarding features require server-side permission. CheckAllowTcpForwarding,PermitOpen,PermitListen, andGatewayPortsbefore assuming a tunnel can listen or connect anywhere. - Firewalls: Remember that firewalls on either the client, server, or intermediate networks can block SSH connections or the ports used for forwarding. Ensure the necessary ports (usually 22 for SSH itself) are open.
- Security: While port forwarding encrypts traffic, the security of the tunnel depends on the security of your SSH server. Use strong SSH keys, disable password authentication, and keep your SSH server updated.
- Reliability: For scripts, add
-o ExitOnForwardFailure=yesso SSH exits if it cannot create the requested forward. For long-running tunnels, considerautosshor a supervised service.
Takeaway
Use -L when your laptop needs to reach a private remote service. Use -R when a remote host needs to reach something near your laptop. Use -D when you need a SOCKS proxy through a trusted SSH server. Keep binds tight, check server policy, and treat every tunnel as a temporary network opening.