SSH Tunnels in Electerm: Local, Remote, Dynamic (SOCKS) and Reverse SOCKS Without the Flags
ssh -L, ssh -R and ssh -D are three of the most useful flags in all of computing — and three of the easiest to mix up. Which side listens? Which side connects? Which direction does traffic flow? Add the fourth form, ssh -R 1080 (a SOCKS proxy that listens on the server), and the confusion doubles.
Electerm puts all four in the bookmark editor as plain L→R, R→L, -D socks and -R socks rows, with live tooltips that show your own host and port back at you. Watch the banner above — one loop cycles through all four modes. That loop is this whole article.
Base reference: How to Use SSH Tunnel. The SSH overview this post belongs to: SSH in Electerm.
The 30-second mental model
Every SSH tunnel rides inside an SSH connection you already have. Two questions settle everything: who listens, and who dials the destination:
| Mode in electerm | CLI equivalent | Who listens | Who dials the destination | Use it when |
|---|---|---|---|---|
L→R forwardLocalToRemote |
ssh -L [localHost:]localPort:remoteHost:remotePort |
your laptop | the server | remote DB, admin UI, internal API |
R→L forwardRemoteToLocal |
ssh -R [remoteHost:]remotePort:localHost:localPort |
the server | your laptop | show a teammate your local dev server, receive a webhook |
-D socks dynamicForward |
ssh -D [localHost:]localPort |
your laptop (SOCKS5) | the server | browse as the server, reach many internal hosts at once |
-R socks remoteDynamicForward |
ssh -R [remoteHost:]remotePort |
the server (SOCKS5) | your laptop | let the server's users reach your network — VPN, intranet, licensed services |
One sentence each:
- L→R: "open an address on my machine that leads to an address on the server's side."
- R→L: "open an address on the server that leads back to an address on my machine."
- -D socks: "open a SOCKS5 proxy on my machine; every connection I send through it exits from the server."
- -R socks: "open a SOCKS5 proxy on the server; every connection sent through it exits from my machine."
The
remoteHostin a tunnel is resolved from the server's point of view.127.0.0.1as remote host means "the server itself", not your laptop. That single fact clears up most tunnel confusion.
The two socks modes are mirror images, and the one thing to remember is where the traffic leaves:
-Dleaves from the server,-R socksleaves from your machine. If you only remember "SOCKS means through the server", the second one will surprise you.
Where tunnels live in electerm
Open any SSH bookmark → scroll to the SSH tunnel section:
- Pick the type: L→R, R→L, -D socks or -R socks. L→R is the default.
- Fill in the side that listens — L→R and R→L want both a local and a remote address, the socks modes want only the listening one. Defaults are
127.0.0.1:12200local and127.0.0.1:12300remote — change them to your real ports. - Give it a name (e.g.
pg-prod,webhook,socks-home) so the list stays readable. - Click the add button. The tunnel appears in the table as
→ local:… → remote:…(orsocks5://…for the socks modes). Hover the?icons any time — the tooltip renders your actual typed values back as a flow diagram. - Save the bookmark and connect. Tunnels come up automatically with the session — no extra click, no background
ssh -fNprocess to babysit.
Need to change one later? Hit the edit pencil in the table row, or the minus icon to delete. A bookmark can hold many tunnels — e.g. Postgres + Redis + admin UI, all on one connection.
Three things worth knowing about how they behave:
- Each tunnel is independent. One failing connection through a tunnel closes just that connection, never the tunnel itself, and the rest keep working.
- Everything dies with the session. Close the SSH connection and all its tunnels are torn down — there is no leftover listener to clean up.
- The remote side is always resolved from the server. That is the one rule that trips people up; the sections below spell it out per mode.
Power-user note: quick-connect strings can carry tunnels too, e.g. ssh://user@host:22?opts={"sshTunnels":[{"sshTunnel":"forwardLocalToRemote","sshTunnelLocalPort":8080,"sshTunnelRemoteHost":"localhost","sshTunnelRemotePort":80}]}.
1. Local → Remote (-L): reach into the server's world
The shape: electerm listens on localHost:localPort on your laptop. Anything you send there is forwarded through the SSH connection to remoteHost:remotePort as seen from the server.
browser → 127.0.0.1:5000 (your laptop)
│ SSH connection
▼
server → remoteHost:6000 (server's network)
Setup (example: remote Postgres only listening on localhost):
- Type: L→R
- Local:
127.0.0.1,5433(use 5433 locally to avoid clashing with your own Postgres on 5432) - Remote:
127.0.0.1,5432 - Name:
pg-prod
Save, connect, then point your client at 127.0.0.1:5433:
psql -h 127.0.0.1 -p 5433 -U app prod
More examples with the same shape:
- Remote admin UI on port 3000 → local
127.0.0.1:5000, openhttp://127.0.0.1:5000. - Internal service reachable only from the server, e.g. remote
10.0.0.8:8080→ local127.0.0.1:8080. Remember: the remote host is resolved by the server, so private VPC addresses work here. - CLI twin:
ssh -L 5433:127.0.0.1:5432 user@server.
Video: Local to Remote SSH Tunnel.
2. Remote → Local (-R): let the server reach back to you
The shape: the server listens on remoteHost:remotePort. Anything connecting there is forwarded back through the SSH connection to localHost:localPort on your laptop.
teammate / webhook → server:6000
│ SSH connection (backwards)
▼
your laptop ← 127.0.0.1:5000
Setup (example: demo your local dev server to someone who can reach the server):
- Type: R→L
- Remote:
127.0.0.1,6000 - Local:
127.0.0.1,5000(wherenpm run devis listening) - Name:
demo-friday
Save, connect, then anyone on the server opening http://127.0.0.1:6000 gets your local :5000.
Other uses:
- Receive a third-party webhook on your laptop via the server's public address.
- Expose a local API to a remote test runner without deploying.
- CLI twin:
ssh -R 6000:127.0.0.1:5000 user@server.
Two gotchas specific to -R:
- If you want the remote port reachable from other machines (not just the server itself), the remote host must be
0.0.0.0and the server needsGatewayPorts yesinsshd_config. Otherwise it stays loopback-only — which is the safe default. - If the remote port is already taken on the server, the tunnel fails to bind. Pick another port.
Video: Remote to Local SSH Tunnel.
3. Dynamic (-D): a SOCKS5 proxy that exits from the server
The shape: electerm listens on localHost:localPort speaking SOCKS5. Point any SOCKS-aware app at it; each connection is forwarded through the SSH connection to whatever destination the app asked for, dialled by the server.
browser --SOCKS5--> 127.0.0.1:1080 (your laptop)
│ SSH connection
▼ dialled by the server
any host on the internet / VPC
Setup:
- Type: -D socks — the remote host/port fields disappear, because there is no single destination.
- Local:
127.0.0.1,1080 - Name:
socks-prod
Save, connect, then:
- Firefox: Settings → Network → SOCKS5
127.0.0.1:1080(enable proxy DNS so names resolve through the server too). - Chrome:
chrome --proxy-server="socks5://127.0.0.1:1080". - curl:
curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me— the returned IP is the server's, proving traffic exits there. - CLI twin:
ssh -D 1080 user@server.
Why dynamic instead of three -L tunnels? When the destinations are many, unknown upfront, or DNS-only-resolvable inside the VPC, one SOCKS proxy replaces an endless list of static forwards.
Video: Dynamic SOCKS Proxy.
4. Reverse SOCKS (-R port): a SOCKS5 proxy on the server that exits from you
The shape: the server listens on remoteHost:remotePort and speaks SOCKS5 to whoever connects there. But when a client asks for db.internal:5432, the connection is dialled by your laptop, not by the server. So the proxy sits on the server's side while the traffic leaves from yours.
apps on the server --SOCKS5--> server:1080
│ SSH connection (backwards)
▼ dialled by your laptop
anything your machine can reach
This is the mode for the case the other three cannot solve: your machine has access the server does not. Corporate VPN on your laptop, a licensed internal service, a database in your home lab, a subnet only your office IP can reach. The server's users get a single socks5://127.0.0.1:1080 and reach all of it — no tunnel per port, no VPN client on the server.
Setup:
- Type: -R socks — the local fields disappear, because nothing listens on your machine.
- Remote:
127.0.0.1,1080(the bind address on the server;0.0.0.0plusGatewayPorts yesif other hosts must reach it) - Name:
vpn-for-server
Save, connect, then on the server:
curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me
# the IP is yours, not the server's — that is the whole point
- CLI twin:
ssh -R 1080 user@server(nohost:hostportafter the port). - It is not a VPN: only TCP through SOCKS5, and only while the session is open.
How it works under the hood, if you want to be sure of the direction: the server's sshd binds the port and, for every connection, opens a forwarded-tcpip channel back to electerm. Electerm runs the SOCKS5 handshake on that channel, and then dials the requested destination with a plain local TCP connection. Nothing about the destination travels back to the server.
Three gotchas:
AllowTcpForwarding noon the server blocks it, exactly like R→L.- Loopback only by default. Other machines on the server's network need
0.0.0.0+GatewayPorts yes, and then you are exposing a proxy into your own network to them — think before you do it. - SOCKS5 only. No SOCKS4; if a legacy client needs it, use
ssh -Ritself.
Troubleshooting checklist
- "Port already in use" locally — another app (or another tunnel) owns
localPort.lsof -i :5433/netstat -tlnp, then pick a free port. Local ports under 1024 need root — stay above them. - Connection refused through the tunnel — the tunnel is up but nothing listens at
remoteHost:remotePortfrom the server. SSH into the server and trycurl remoteHost:remotePortthere first. For-R socksthe roles flip: check the destination from your machine. - Wrong
remoteHostperspective —127.0.0.1means the server itself. If the target is your laptop, you picked the wrong direction (you want R→L, not L→R). - R→L or -R socks reachable only on the server — expected without
GatewayPorts yes+ remote host0.0.0.0. That is a server-sidesshd_configchange, not an electerm bug. - Tunnel dies with the session — by design: tunnels are bound to the SSH connection lifecycle (
conn.on('close')tears them down). Reconnect and they come back; for work that must survive the network, run the payload inside tmux as well. - Server forbids forwarding —
AllowTcpForwarding no(orDisableForwarding) on the server blocks all four modes. Needs a server admin to relax. - SOCKS app ignores the proxy — many apps need per-app proxy settings and remote DNS enabled; a quick
curl --socks5-hostnametest separates "tunnel broken" from "app not using the tunnel". -Dand-R socksconfused — check where the traffic leaves.-Dlistens on your laptop and exits from the server;-R sockslistens on the server and exits from your laptop.curl https://ifconfig.methrough the proxy tells you which one you actually built.
Cheat-sheet
- Reach something near the server → L→R (
ssh -L localPort:remoteHost:remotePort). Local port is yours, remote address is the server's view. - Let the server reach your laptop → R→L (
ssh -R remotePort:localHost:localPort). NeedsGatewayPortsfor non-loopback exposure. - Reach many things as the server → -D socks (
ssh -D localPort), point the app atsocks5://127.0.0.1:localPort. - Let the server's users reach your network → -R socks (
ssh -R remotePort), point their apps atsocks5://127.0.0.1:remotePorton the server. - In electerm: bookmark → tunnel section → type + hosts + ports + name → add → save → connect. Edit with the pencil, delete with the minus. Many tunnels per bookmark are fine.
- Tunnels start with the session and die with it — one connection, zero stray
ssh -fNprocesses.
Next: SSH in Electerm for auth, jump hosts and NetBird that pair with these tunnels — or Session Keepalive if your long-lived tunneled sessions keep getting idle-killed.
