Guide
What is an SSH tunnel? SSH port forwarding explained
An SSH tunnel sends another program's network connection through an encrypted SSH connection. It's also called SSH port forwarding. A local forward (ssh -L) lets you reach a service the server can see, a remote forward (ssh -R) lets the server reach a service on your computer, and a dynamic forward (ssh -D) turns the connection into a SOCKS proxy.
Tunnels are the simple way to reach a database, an admin page or a desktop that isn't open to the internet, with nothing but the SSH port open. Here's how each kind works, with commands you can copy.
- Local -L
- Remote -R
- Dynamic -D (SOCKS)
Updated · OpenSSH on Linux, macOS and Windows 10 and 11
How an SSH tunnel works
You start with an SSH connection to a server, usually on port 22 (if the server doesn't run SSH yet, enable SSH on Ubuntu or Debian first). A tunnel adds a second channel inside that connection. With a local forward, for example:
your app --> localhost:5433 on your computer
--> encrypted SSH connection (port 22) -->
server --> localhost:5432 on the server (the database)Your app thinks the database is on your own computer. ssh carries the bytes to the server, and the server makes the last hop. Only the SSH port has to be reachable, and the part between you and the server is encrypted. The last hop, from the server to the target, is an ordinary connection: often that's the server talking to itself, which is ideal.
The three kinds at a glance
| Kind | Example | Port opens on | Use it to |
|---|---|---|---|
| Local (-L) | ssh -L 5433:localhost:5432 user@server | Your computer | Reach a service only the server can see. |
| Remote (-R) | ssh -R 9000:localhost:3000 user@server | The server | Let the server reach a service on your computer. |
| Dynamic (-D) | ssh -D 1080 user@server | Your computer (SOCKS) | Send a browser or app's traffic out from the server. |
Local port forwarding (ssh -L)
The pattern is ssh -L local_port:target_host:target_port user@ssh_server. The target is seen from the server's side, so localhost means the server itself.
# a database that only listens on the server itself ssh -L 5433:localhost:5432 admin@db.example.com # an admin page on the server's private network ssh -L 8443:192.168.10.5:443 admin@gateway.example.com # a desktop shared over VNC on the server ssh -L 5901:localhost:5900 admin@desktop.example.com
While ssh runs, point your program at localhost and the local port: the database tool at localhost:5433, the browser at https://localhost:8443 (it may warn that the certificate's name doesn't match), the VNC viewer at localhost:5901. Add -N to forward without opening a shell, and -f to send ssh to the background. One command can carry several -L options.
Remote port forwarding (ssh -R)
Remote forwarding is the mirror image: the port opens on the server and leads back to your side.
ssh -R 9000:localhost:3000 admin@server.example.com
On the server, localhost:9000 now reaches port 3000 on your computer, for example a web app you're developing that the server needs to call. By default the port only listens on the server's own loopback, so other machines can't use it. The server setting GatewayPorts changes that; leave it at its default (no) unless you mean to share the port.
Dynamic port forwarding (ssh -D): a SOCKS proxy
ssh -D 1080 -N admin@server.example.com # then, for example: curl --socks5-hostname localhost:1080 http://intranet.example.internal/
-D starts a SOCKS proxy on your computer. Any program you set to use the SOCKS5 proxy at localhost, port 1080, makes its connections from the server, so it can reach what the server reaches, names included. It's also how you can send other SSH connections through one server: see connecting to SSH servers through a SOCKS or HTTP proxy.
Hopping through a server: ProxyJump instead of a tunnel
To SSH to a machine that's only reachable through another one (a jump host or bastion), you don't need to build a tunnel by hand. ssh does it for you:
ssh -J admin@bastion.example.com admin@10.0.0.5
Save it as ProxyJump in your SSH config file and the hop happens every time. Your keys stay on your computer; the bastion only passes the encrypted connection along.
SSH agent forwarding
Agent forwarding (ssh -A, or ForwardAgent yes for one host in your config) lets programs on the server use the keys loaded in your computer's ssh-agent, for example to fetch code from a repository with your key, without copying the key to the server.
The catch: while you're connected, anyone with root on that server can use your agent to sign in as you elsewhere. Only forward your agent to servers you trust, never set it for Host *, and use ProxyJump rather than agent forwarding to hop between servers. Setting up the agent itself is in the guide to passwordless SSH with keys.
Keep SSH tunnels safe
- Keep forwarded ports on localhost. That's the default. Writing
-L 0.0.0.0:5433:...or adding-gopens the port to your whole network. - Close tunnels when you're done. Use
-Nfor tunnel-only sessions, and-o ExitOnForwardFailure=yesso ssh stops if it can't open the port instead of carrying on without it. - Remember the last hop. Only the part between you and the SSH server is encrypted by the tunnel. Beyond the server, the connection is whatever the protocol itself is.
- Ask before you tunnel out of a network you don't run. A tunnel goes around the firewall's rules, so check it's allowed.
- Server admins decide. In
sshd_config,AllowTcpForwarding noturns tunnels off for everyone or (inside aMatchblock) for some users, andPermitOpenlimits where local forwards may go. - Keep idle tunnels alive.
-o ServerAliveInterval=60stops a router dropping a quiet connection.
SSH tunnels in RemoteAccessApp, without the command line
In the RemoteAccessApp SSH client, a saved SSH host can carry its own port forwards, which start when you open its terminal. It's free, in the Console for Windows and Linux:
Step 1: Edit the SSH host
On Connections, right-click the host and choose Edit. Open Advanced, then Port forwarding.
Step 2: Add a forward
Pick the kind: This PC's port to the server (like
ssh -L), Server port to this PC (likessh -R) or SOCKS proxy on this PC (likessh -D). Enter the port that should listen and, for the first two, where the connection goes.Step 3: Save and connect
Open the host's terminal. A strip above it says how many forwards are running and, if one couldn't start, why (a port already in use, or a server that doesn't allow forwarding). Closing the terminal stops them.
Good to know
Want to try it? Download RemoteAccessApp; it's free for up to 5 saved hosts. If your server listens on an SSH port other than 22, put that in the host's Port box; the forwards use the same connection.
Questions, answered
Related
- SSH through a proxyWhen an SSH connection has to go through a proxy, and how to set one per host in the Windows app.Read the guide
- SSH config file examplesWhere ~/.ssh/config lives on each system, how ssh reads it, and copy-ready examples for aliases, ports, keys, jump hosts and keep-alives.Read the guide
- Passwordless SSH with keysMake an SSH key, copy it to the server with ssh-copy-id (or one PowerShell line on Windows), get the permissions right and sign in without a password.Read the guide
- SSH port 22SSH and SFTP use port 22. Connect on another port with ssh -p, change the port on a Linux or Windows server, and check it's open.Read the guide
- SSH & SFTP clientTerminal tabs, an SFTP and FTP file manager, key sign-in and one command to every server.Learn more
- RDP & VNC managerSave RDP, VNC, SSH, SFTP, FTP hosts and web admin panels in one list, and open them in tabs.Learn more
