SSH tunnels are a fast, secure way to reach services that should not be exposed to the public internet (databases, admin panels, internal APIs, message brokers, …). You create an encrypted SSH connection to a server, and SSH forwards traffic between a port on one side and a destination on the other.
Local Port Forwarding (-L)
Goal: You want to connect from your local computer to a service that is reachable from machine (often only inside its network, or only on its own loopback).
Typical situation:
You (on your laptop) want to open your database GUI / browser / CLI locally and connect to something that lives behind machine:
- a service running on
machineitself (often bound to127.0.0.1) - a service on another internal host (e.g.
host) only reachable frommachine
Example: Open local port 1234 and forward it to host:9876 through machine:
ssh -L 1234:host:9876 root@machine -NnT How it works
- You SSH into
machine. - Your local port
localhost:1234becomes a secure entry point. - Anything connecting to
localhost:1234on your laptop is forwarded through SSH and reacheshost:9876as seen frommachine.
Common real-world uses
- Database access (local tool → remote DB): Your local app (DBeaver, MySQL CLI, psql, …) connects to
localhost:PORT, which is forwarded to a database that listens only on127.0.0.1onmachineor on an internal host. - Admin UIs (browser → internal web app): You open
http://localhost:PORTin your browser to reach a private admin panel available only inside the server network. - Internal APIs (local dev → staging service): Your local code talks to
localhost:PORTand actually hits a protected API endpoint inside the remote environment.
Reverse Port Forwarding (-R)
Goal: A process running on machine (or someone logged into it) needs to connect to a service running on your local computer—even though your computer is behind NAT/firewall and cannot be reached directly.
Typical situation:
A remote script / service / coworker on machine wants to reach a service on your laptop (e.g. a local dev server, webhook receiver, debug endpoint).
Example: Open port 1234 on machine that forwards back to your local 9876:
ssh -R 1234:localhost:9876 root@machine -NnT How it works
- You SSH into
machine. machine:1234becomes the entry point on the remote side.- When something on
machineconnects tolocalhost:1234, SSH forwards the traffic back to your laptop’slocalhost:9876.
Common real-world uses
- Webhooks/callbacks (remote system → your local endpoint): You run a local server for testing and make it reachable from
machineto receive callbacks. - Remote debugging (remote process → local debugger UI): A remote app can connect back to a local debug port through the tunnel.
- Temporary sharing (remote teammate → your local service): A teammate on
machinecan try your local prototype without you deploying it anywhere.
Note: Often, the forwarded port on machine is bound to its localhost by default (depends on SSH server config). If you want it reachable from other machines, you may need:
-R 0.0.0.0:1234:localhost:9876and/orGatewayPorts yesin the remote SSH server config (sshd)
SSH Tunnel to a Unix Domain Socket
Goal: You want to connect from your local computer to a service that listens on a Unix socket on machine (not on a TCP port).
Typical situation:
Your local client (DB tool, script) can only speak TCP but the service on machine is configured for socket-only local access (common for MySQL/MariaDB).
Example: Forward local TCP 1234 to the remote socket /var/run/mysql.sock on machine:
ssh -L 1234:/var/run/service.sock root@machine -NnT Why this is useful
- Many services intentionally avoid TCP listeners for security.
- You can still access them safely without changing server configuration.
Example: Open a Local MySQL Port for a Remote DB
Forward local port 3307 to the MySQL instance on machine that listens on 127.0.0.1:3306:
ssh -L 3307:127.0.0.1:3306 root@machine -NnT or that listens on /var/run/mysql.sock on machine:
ssh -L 1234:/var/run/mysql.sock root@machine -NnT Now connect locally as if MySQL were on your computer:
mysql -h 127.0.0.1 -P 3307 -u youruser -p Tip: Using 127.0.0.1 instead of localhost can prevent some clients from trying a local socket instead of TCP.
What the flags mean (-NnT) and why they matter
-N— do not run a remote command (tunnel only)-n— redirect stdin from/dev/null(prevents hanging on input)-T— disable pseudo-terminal allocation (cleaner for non-interactive use)
Useful additions:
-v/-vv— debug tunnel problems-o ExitOnForwardFailure=yes— fail fast if the bind/forward cannot be established-o ServerAliveInterval=30 -o ServerAliveCountMax=3— keep tunnels alive over flaky links
Example with safety options:
ssh -L 3307:127.0.0.1:3306 root@machine -NnT \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 -o ServerAliveCountMax=3 Quick mental model
-L(Local): “I connect locally → forwarded to remote destination viamachine.”-R(Reverse): “Remote connects onmachine→ forwarded back to my local machine.”- Unix socket forwarding: “Expose a remote socket on
machineas a local TCP port.”
Practical security notes
-
By default, local forwards bind to
127.0.0.1(good: only you can access them on your laptop).- If you want LAN access:
-L 0.0.0.0:1234:host:9876(be careful).
- If you want LAN access:
-
Avoid SSHing as
rootunless necessary. A dedicated user + least privileges is usually better. -
For long-running tunnels, consider
~/.ssh/configentries andautosshfor automatic reconnects.