How to forward ports with SSH tunneling - Rocketeers app

  [ Rocketeers ](/)   

[Login](https://rocketeersapp.com/login) 

 On this page

 Knowledge
---------

How to forward ports with SSH tunneling
=======================================

### [\#CommandLine](https://rocketeersapp.com/knowledge/command-line)

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](https://rocketeersapp.com/author/mark-van-eijk) on June 23, 2026 · 2 minute read

1. [What SSH tunneling is for](#content-what-ssh-tunneling-is-for)
2. [Local forwarding (-L)](#content-local-forwarding--l)
3. [Remote forwarding (-R)](#content-remote-forwarding--r)
4. [Dynamic forwarding (-D)](#content-dynamic-forwarding--d)
5. [The -N and -f flags](#content-the--n-and--f-flags)

[\#](#content-what-ssh-tunneling-is-for "Permalink")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](/connect-to-server-ssh-command).

There are three kinds of forwarding worth knowing.

[\#](#content-local-forwarding--l "Permalink")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`.

[\#](#content-remote-forwarding--r "Permalink")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`.

[\#](#content-dynamic-forwarding--d "Permalink")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.

[\#](#content-the--n-and--f-flags "Permalink")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!

  Fill in your email address to receive updates  Subscribe 

#### More in [\#CommandLine](https://rocketeersapp.com/knowledge/command-line)

- [Argument list too long (Bash: /bin/rm)](https://rocketeersapp.com/knowledge/argument-list-too-long)
- [How to install Composer packages locally](https://rocketeersapp.com/knowledge/install-composer-packages-locally)
- [How to send GET and POST requests with curl](https://rocketeersapp.com/knowledge/curl-post-get-api-requests)
- [Essential Linux command line basics for developers](https://rocketeersapp.com/knowledge/linux-command-line-basics)
- [How to search file contents with grep](https://rocketeersapp.com/knowledge/search-files-grep-command)
- [The complete guide to the curl command](https://rocketeersapp.com/knowledge/curl-command-complete-guide)

 [View all 21 articles →](https://rocketeersapp.com/knowledge/command-line)
