Guides · IP & network · Updated

SSH port forwarding explained: local, remote and dynamic

SSH port forwarding (also called SSH tunnelling) carries traffic for one port through an encrypted SSH connection. Local forwarding (-L) reaches a service behind a server, remote forwarding (-R) exposes your own service through a server, and dynamic forwarding (-D) makes a SOCKS proxy.

Check a port first

Test whether a port on a public host is reachable from the internet:

Local forwarding: -L

Opens a port on your machine and forwards it, through the SSH server, to a destination.

ssh -L 8080:localhost:80 user@server.example.com

Now http://localhost:8080 on your computer reaches port 80 as seen from the server. The form is -L local_port:destination_host:destination_port.

A common use is reaching a database that only accepts connections from inside a network:

ssh -L 5433:db.internal.example:5432 user@bastion.example.com
psql -h localhost -p 5433 mydb

Remote forwarding: -R

Opens a port on the SSH server and forwards it back to a destination reachable from your machine.

ssh -R 9000:localhost:3000 user@server.example.com

Anyone on the server can now reach your local port 3000 at localhost:9000 there. This is how you share a development site from behind a router without opening a port. By default the server binds it to its loopback address only; exposing it publicly needs GatewayPorts enabled in the server's configuration, which should be a deliberate choice. Compare with port forwarding on a router.

Dynamic forwarding: -D

ssh -D 1080 user@server.example.com

This starts a SOCKS proxy on localhost:1080. Set a browser or program to use it and its traffic leaves from the server. It behaves like a small VPN for those programs.

Useful flags

FlagEffect
-NDon't run a remote command. Use it when you only want the tunnel.
-fGo to the background after connecting.
-J hostJump through another host first.
-p portConnect to an SSH server that isn't on port 22.
ssh -fN -L 8080:localhost:80 user@server.example.com

Troubleshooting

  • "bind: Address already in use". Something already listens on that local port. Pick another, or find the process with the steps in how to check open ports.
  • "channel open failed: administratively prohibited". The server's AllowTcpForwarding setting forbids it. An administrator has to allow it.
  • "connect failed: Connection refused". The tunnel works but nothing listens at the destination you named.
  • The tunnel drops when idle. Add -o ServerAliveInterval=60 to keep it alive.

Security notes

  • Bind forwards to localhost (the default) so nobody else on your network can use them.
  • A tunnel can reach services that a firewall was meant to protect. On servers where you don't need forwarding, turn it off with AllowTcpForwarding no.
  • Use keys, not passwords, for connections you leave running.

Frequently asked questions

What is SSH port forwarding?

It carries network traffic from one port through an encrypted SSH connection to another machine, so you can reach a service that is not exposed directly.

What is the difference between -L and -R?

With -L (local) a port on your machine forwards to a destination reached from the SSH server. With -R (remote) a port on the SSH server forwards back to a destination reached from your machine.

What does ssh -D do?

It starts a SOCKS proxy on a local port. Programs set to use that proxy send all their traffic through the SSH server.

Is SSH port forwarding secure?

The traffic between your machine and the server is encrypted. But a tunnel can also expose an internal service, so bind it to localhost and turn forwarding off on servers where you do not need it.

Why does my forwarded port say "address already in use"?

Another program, or an earlier tunnel, is already listening on that local port. Choose a different local port or stop the other process.