# A Practical Guide to SSH Tunnels: Local and Remote Port Forwarding

> Mnemonics and labs for the four SSH tunneling modes: local (-L), remote (-R), dynamic (-D), and remote-dynamic. Covers bastion hosts and SOCKS proxies.

Published: 2026-06-19
URL: https://daniliants.com/insights/ssh-tunnels-local-and-remote-port-forwarding/
Tags: devops, self-hosting, ssh, port-forwarding

---

## Summary

A hands-on reference for the four SSH tunneling modes (local `-L`, remote `-R`, dynamic `-D`, and remote-dynamic `-R` with no destination), each demonstrated against a 4-host / 3-network lab. The core value is the exact flag syntax plus a mental model for which side starts listening and which direction traffic flows.

## Key Insight

- **Two mnemonics resolve all confusion:** `-L` (local) = the SSH *client* opens the listening port; `-R` (remote) = the *sshd server* opens the listening port. Direction follows from who listens.
- **`-L` can target any machine, not just the SSH server.** In `ssh -L 8081:172.16.0.40:80 bastion`, the forward target (`172.16.0.40`) and the SSH server (`bastion`) are different hosts, the bastion opens a second hop on your behalf. This is the classic "reach a VPC-private OpenSearch/DB via a public EC2 jump host" pattern.
- **`-R` has a hidden pitfall:** by default the exposed port binds only to the gateway's `localhost`, so it's reachable only from inside the gateway. To expose to the public internet you must set `GatewayPorts yes` in the gateway's `sshd_config`, then bind `0.0.0.0:port`.
- **Dynamic forwarding (`-D`) beats N separate `-L` tunnels.** One `ssh -D 1080 bastion` turns the client into a SOCKS proxy reaching *every* host behind the bastion; with `-L` you'd need one tunnel per destination. Client must speak SOCKS (`curl --socks5-hostname localhost:1080 ...`).
- **Remote dynamic forwarding** (`ssh -R port` with no destination) mirrors `-D`: it makes the *gateway* a SOCKS proxy that tunnels back to the client, exposing an entire home/private network through one proxy. Needs OpenSSH 7.6+ on the client.
- **Background pattern:** add `-f -N` to any of these (`ssh -f -N -L ...`) to run the tunnel detached with no remote shell.