Console9

How to create an SSH tunnel for port forwarding

Forward local or remote ports through an encrypted SSH tunnel to access services behind firewalls or NAT.

Forward a local port to a remote service through an encrypted SSH connection, enabling access to databases, web servers, and internal services behind firewalls.

Prerequisites

  • SSH client installed on the local machine
  • SSH access to the remote server (the tunnel endpoint)
  • The target service's hostname/IP and port (as reachable from the SSH server)

Step-by-Step: Create an SSH Tunnel for Port Forwarding

1. Create a Local Port Forward with SSH

The SSH -L flag binds a local port and forwards traffic through the SSH connection to a remote destination:

ssh -L 3306:localhost:3306 user@203.0.113.50

The SSH tunnel maps local port 3306 to port 3306 on the remote server. The localhost in the middle refers to the remote server's perspective — it connects to its own port 3306. After the tunnel is established, connect to localhost:3306 on the local machine to reach the remote MySQL server.

2. Create a Background SSH Tunnel

The SSH -f and -N flags run the tunnel in the background without opening a remote shell:

ssh -f -N -L 5432:db.internal:5432 user@203.0.113.50

The -f flag backgrounds the SSH process after authentication. The -N flag prevents SSH from executing any remote commands. The SSH tunnel forwards local port 5432 to db.internal:5432 as reachable from the SSH server.

3. Create a Dynamic SOCKS Proxy with SSH

The SSH -D flag creates a SOCKS5 proxy that routes all traffic through the SSH connection:

ssh -D 1080 -f -N user@203.0.113.50

Configure the browser or application to use localhost:1080 as a SOCKS5 proxy. All traffic flows through the encrypted SSH tunnel to the remote server.

How to Verify the SSH Tunnel Is Working

Test the forwarded port with cURLor a database client connecting to the local port:

curl http://localhost:8080

If the SSH tunnel forwards port 8080 to a remote web server, cURL returns the remote server's response.

Common Issues When Creating SSH Tunnels

"bind: Address already in use"— Another process already occupies the local port. Find it with lsof -i :3306 and stop it, or choose a different local port: ssh -L 13306:localhost:3306 user@host.

Tunnel connects but no data flows— The target service may only accept connections from specific IP addresses. Since the tunnel terminates at the SSH server, the target sees the connection from the SSH server's IP, not from the local machine.