Knowledge

How to forward ports with SSH tunneling

#CommandLine

Forward ports over SSH with local, remote, and dynamic SOCKS tunnels, including reaching a remote MySQL database safely from your laptop.

Published by Mark van Eijk on June 23, 2026 · 2 minute read

  1. What SSH tunneling is for
  2. Local forwarding (-L)
  3. Remote forwarding (-R)
  4. Dynamic forwarding (-D)
  5. The -N and -f flags

What SSH tunneling is for

SSH can do more than give you a shell: it can carry other connections through its encrypted channel. I lean on this constantly to reach services that aren't exposed to the internet, like a database bound to localhost on a remote server. If you're new to the ssh command itself, start with connecting to a server with ssh.

There are three kinds of forwarding worth knowing.

Local forwarding (-L)

Local forwarding makes a remote service appear on a port of your own machine. The syntax is -L local_port:target_host:target_port:

ssh -L 8080:localhost:80 jane@app.example.com

Here localhost:80 is resolved from the server's perspective, so this exposes the server's local web service on http://localhost:8080 on your laptop.

The classic use is a database. Say MySQL on the server listens on 3306 but isn't reachable from outside. Tunnel it:

ssh -L 3306:localhost:3306 jane@app.example.com

Now point your local MySQL client at 127.0.0.1:3306 and you're talking to the remote database over SSH. If 3306 is already busy locally, just pick another local port like -L 13306:localhost:3306.

Remote forwarding (-R)

Remote forwarding is the reverse: it exposes a port on your machine to the server. The syntax is -R remote_port:target_host:target_port. This is handy for letting a remote box reach a service running on your laptop, for example a webhook receiver during development:

ssh -R 9000:localhost:3000 jane@app.example.com

Now connections to port 9000 on the server are forwarded to your local port 3000.

Dynamic forwarding (-D)

Dynamic forwarding turns SSH into a local SOCKS proxy, routing whatever you send through it out via the server. Point a browser or tool at the SOCKS port and your traffic exits from the server:

ssh -D 1080 jane@app.example.com

Configure your application to use 127.0.0.1:1080 as a SOCKS5 proxy. This is great for reaching internal services that are only allowed from the server's network.

The -N and -f flags

When you're tunnelling, you usually don't want an interactive shell as well. Two flags help:

  • -N tells SSH not to run a remote command (just forward), so you don't get a shell prompt.
  • -f sends SSH to the background after authenticating.

Combined, they give you a clean background tunnel:

ssh -fN -L 3306:localhost:3306 jane@app.example.com

That command sets up the MySQL tunnel and returns your prompt immediately. To shut it down later, find and kill it:

pkill -f "3306:localhost:3306"

Once you've got the -L, -R, and -D shapes memorised, you can punch a secure path to almost any service without exposing it to the open internet.

Subscribe to our newsletter

Do you want to receive regular updates with fresh and exclusive content to learn more about web development, hosting, security and performance? Subscribe now!

Related articles

Argument list too long (Bash: /bin/rm)

Forward ports over SSH with local, remote, and dynamic SOCKS tunnels, including reaching a remote MySQL database safely from your laptop.

Read more →

How to install Composer packages locally

Forward ports over SSH with local, remote, and dynamic SOCKS tunnels, including reaching a remote MySQL database safely from your laptop.

Read more →