SSH Tunnel: Local, Remote, and Dynamic Port Forwarding

SSH tunneling (SSH port forwarding) is a method of creating an encrypted SSH connection between a client and a server through which service ports can be relayed.
SSH tunneling is useful for transporting network data of services that use an unencrypted protocol, such as VNC or FTP , accessing geo-restricted content, or bypassing intermediate firewalls. You can forward any TCP port and tunnel the traffic over a secure SSH connection.
Common use cases for SSH port forwarding include secure remote access to internal services, creating a temporary SOCKS proxy for browsing, and exposing a local dev server to a remote machine.
There are three types of SSH port forwarding:
- Local Port Forwarding: Forwards a connection from the client host to the SSH server host and then to the destination host port.
- Remote Port Forwarding: Forwards a port from the server host to the client host and then to the destination host port.
- Dynamic Port Forwarding: Creates a SOCKS proxy server that allows communication across a range of ports.
This guide explains how to set up local, remote, and dynamic encrypted SSH tunnels.
Quick Reference
For a printable quick reference, see the ssh cheatsheet .
| Task | Command |
|---|---|
| Local port forwarding | ssh -L 8080:localhost:80 user@server |
| Remote port forwarding | ssh -R 8080:localhost:3000 user@server |
| Dynamic port forwarding (SOCKS) | ssh -D 9090 user@server |
| Run tunnel in background | ssh -L 8080:localhost:80 -N -f user@server |
| Multiple local forwards | ssh -L 8080:host1:80 -L 8081:host2:80 user@server |
| Jump host | ssh -J jump.host user@destination |
Local Port Forwarding
Local port forwarding allows you to forward a port on the local (SSH client) machine to a port on the remote (SSH server) machine, which is then forwarded to a port on the destination machine.
In this forwarding type, the SSH client listens on a given port and tunnels any connection to that port to the specified port on the remote SSH server, which then connects to a port on the destination machine. The destination machine can be the remote SSH server or any other machine.
Local port forwarding is mostly used to connect to a remote service on an internal network, such as a database or VNC server.
In Linux, macOS, and other Unix systems, to create a local port forwarding, pass the -L option to the ssh client:
ssh -L [LOCAL_IP:]LOCAL_PORT:DESTINATION:DESTINATION_PORT [USER@]SSH_SERVERThe options used are as follows:
[LOCAL_IP:]LOCAL_PORT- The local machine IP address and port number. WhenLOCAL_IPis omitted, the ssh client binds on the localhost.DESTINATION:DESTINATION_PORT- The IP or hostname and the port of the destination machine.[USER@]SSH_SERVER- The remote SSH user and server IP address.
You can use any port number greater than 1024 as a LOCAL_PORT. Port numbers less than 1024 are privileged ports and can be used only by root. If your SSH server is listening on a port other than 22
(the default), use the -p [PORT_NUMBER] option.
The destination hostname must be resolvable from the SSH server.
Say you have a MySQL database server running on machine db001.host on an internal (private) network, on port 3306, which is accessible from the machine pub001.host, and you want to connect using your local machine’s MySQL client to the database server. To do so, you can forward the connection using the following command:
ssh -L 3336:db001.host:3306 user@pub001.hostOnce you run the command, you will be prompted to enter the remote SSH user password. Once entered, you will be logged into the remote server, and the SSH tunnel will be established. It is also a good idea to set up an SSH key-based authentication and connect to the server without entering a password.
Now, if you point your local machine database client to 127.0.0.1:3336, the connection will be forwarded to the db001.host:3306 MySQL server through the pub001.host machine that acts as an intermediate server.
You can forward multiple ports to multiple destinations in a single ssh command. For example, if you have another MySQL database server running on machine db002.host and you want to connect to both servers from your local client, you would run:
ssh -L 3336:db001.host:3306 -L 3337:db002.host:3306 user@pub001.hostTo connect to the second server, you would use 127.0.0.1:3337.
When the destination host is the same as the SSH server, instead of specifying the destination host IP or hostname, you can use localhost.
Say you need to connect to a remote machine through VNC, which runs on the same server, and it is not accessible from the outside. The command you would use is:
ssh -L 5901:127.0.0.1:5901 -N -f user@remote.hostThe -f option tells the ssh command to run in the background and -N not to execute a remote command. We are using 127.0.0.1 because the VNC and the SSH server are running on the same host.
If you are having trouble setting up tunneling, check your remote SSH server configuration and make sure AllowTcpForwarding is not set to no. By default, forwarding is allowed.
Remote Port Forwarding
Remote port forwarding is the opposite of local port forwarding. It allows you to forward a port on the remote (SSH server) machine to a port on the local (SSH client) machine, which is then forwarded to a port on the destination machine.
In this forwarding type, the SSH server listens on a given port and tunnels any connection to that port to the specified port on the local SSH client, which then connects to a port on the destination machine. The destination machine can be the local or any other machine.
In Linux, macOS, and other Unix systems, to create a remote port forwarding, pass the -R option to the ssh
client:
ssh -R [REMOTE:]REMOTE_PORT:DESTINATION:DESTINATION_PORT [USER@]SSH_SERVERThe options used are as follows:
[REMOTE:]REMOTE_PORT- The bind address and port number on the remote SSH server. IfREMOTEis omitted, the listening address is controlled by the SSH server’sGatewayPortssetting. To make the port reachable from other hosts, use an explicit bind address such as0.0.0.0when the server allows it.DESTINATION:DESTINATION_PORT- The IP or hostname and the port of the destination machine.[USER@]SSH_SERVER- The remote SSH user and server IP address.
Remote port forwarding is mostly used to give access to an internal service to someone from the outside.
Say you are developing a web application on your local machine, and you want to show a preview to your fellow developer. You do not have a public IP, so the other developer cannot access the application via the Internet.
If you have access to a remote SSH server, you can set up a remote port forwarding as follows:
ssh -R 8080:127.0.0.1:3000 -N -f user@remote.hostThe command above will make the ssh server listen on port 8080, and tunnel all traffic from this port to your local machine on port 3000.
Now your fellow developer can type the_ssh_server_ip:8080 in their browser and preview your application.
If you are having trouble setting up remote port forwarding, make sure GatewayPorts is set to yes in the remote SSH server configuration.
To bind the remote forwarding port on all interfaces, specify an explicit bind address, for example:
ssh -R 0.0.0.0:8080:127.0.0.1:3000 -N -f user@remote.hostBinding to 0.0.0.0 makes the forwarded port accessible from outside the SSH server, so use it only when necessary.
Dynamic Port Forwarding
Dynamic port forwarding allows you to create a socket on the local (SSH client) machine, which acts as a SOCKS proxy server. When a client connects to this port, the connection is forwarded to the remote (SSH server) machine, which is then forwarded to a dynamic port on the destination machine.
This way, all the applications using the SOCKS proxy will connect to the SSH server, and the server will forward all the traffic to its actual destination.
In Linux, macOS, and other Unix systems, to create a dynamic port forwarding (SOCKS), pass the -D option to the ssh client:
ssh -D [LOCAL_IP:]LOCAL_PORT [USER@]SSH_SERVERThe options used are as follows:
[LOCAL_IP:]LOCAL_PORT- The local machine IP address and port number. WhenLOCAL_IPis omitted, the SSH client binds on localhost.[USER@]SSH_SERVER- The remote SSH user and server IP address.
A typical example of dynamic port forwarding is tunneling web browser traffic through an SSH server.
The following command will create a SOCKS tunnel on port 9090:
ssh -D 9090 -N -f user@remote.hostOnce the tunneling is established, you can configure your application to use it. This article explains how to configure Firefox and Google Chrome browser to use the SOCKS proxy.
The port forwarding has to be separately configured for each application that you want to tunnel the traffic through.
Using SSH Config File for Tunnels
Instead of typing long ssh commands each time, you can define tunnels in your SSH config file
(~/.ssh/config):
Host tunnel-db
HostName pub001.host
User user
LocalForward 3336 db001.host:3306
Host tunnel-socks
HostName remote.host
User user
DynamicForward 9090With this configuration, you can start a tunnel by simply running:
ssh -N tunnel-dbSet up SSH Tunneling in Windows
Windows 10 and later include a built-in OpenSSH client. You can use the same ssh commands shown above directly in PowerShell or Command Prompt.
To verify that OpenSSH is installed, open PowerShell and run:
ssh -VIf the command returns a version number, OpenSSH is available and you can use all the -L, -R, and -D options described in the previous sections.
Using PuTTY
Alternatively, you can use the PuTTY SSH client. You can download PuTTY here .
Launch PuTTY and enter the SSH server IP Address in the
Host name (or IP address)field.
Under the
Connectionmenu, expandSSHand selectTunnels. Check theLocalradio button to set up local,Remotefor remote, andDynamicfor dynamic port forwarding.- When setting up local forwarding, enter the local forwarding port in the
Source Portfield and inDestinationenter the destination host and IP, for example,localhost:5901. - For remote port forwarding, enter the remote SSH server forwarding port in the
Source Portfield and inDestinationenter the destination host and IP, for example,localhost:3000. - If setting up dynamic forwarding, enter only the local SOCKS port in the
Source Portfield.

- When setting up local forwarding, enter the local forwarding port in the
Click on the
Addbutton, as shown in the image below.
Go back to the
Sessionpage to save the settings so that you do not need to enter them each time. Enter the session name in theSaved Sessionfield and click on theSavebutton.
Select the saved session and log in to the remote server by clicking on the
Openbutton.
A new window asking for your username and password will show up. Once you enter your username and password, you will be logged in to your server, and the SSH tunnel will be started.
Setting up public key authentication allows you to connect to your server without entering a password.
Common SSH Tunneling Options
Here are some useful options you can combine with SSH tunnels:
-N- Do not execute a remote command. Useful when you only want to forward ports.-f- Run SSH in the background after authentication.-L- Set up local port forwarding.-R- Set up remote port forwarding.-D- Set up dynamic port forwarding (SOCKS proxy).-o ExitOnForwardFailure=yes- Exit if the tunnel cannot be established.-o ServerAliveInterval=60- Send keep-alives to keep long-lived tunnels up.-p- Specify the SSH server port (if not the default 22).-J- Use a jump host (ProxyJump) to reach a server through an intermediate host. For example:ssh -J jump.host user@destination.host.
FAQ
What is the difference between local and remote port forwarding?
Local forwarding listens on your local machine and forwards traffic to a remote destination. Remote forwarding listens on the remote server and forwards traffic back to your local machine or another host.
Can I forward UDP traffic through an SSH tunnel?
No, SSH tunnels only support TCP traffic. For UDP forwarding, you would need tools like socat or a VPN solution.
How do I close a background SSH tunnel?
Find the process with ps aux | grep ssh and terminate it with kill <PID>. Alternatively, use -o ExitOnForwardFailure=yes and -o ServerAliveInterval=60 to make tunnels self-managing.
Is SSH tunneling secure?
Yes, all traffic through the tunnel is encrypted by the SSH connection. However, the traffic between the SSH server and the final destination is not encrypted by the tunnel itself.
Conclusion
For ease of use, define your tunnels in the SSH config file
so you can start any tunnel with ssh -N tunnel-name instead of typing the full command each time.
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page