Secure SSH tunnels: local, remote and dynamic forwarding
Reach a private Docker dashboard without exposing it to the Internet. Understand -L, -R and -D and choose safe bind addresses.
SSH forwarding reaches a service available only on a server or its private network without publishing another Internet-facing port. The common case is local forwarding with ssh -N -L.
Local forwarding: ssh -L
ssh -N -L 127.0.0.1:8790:127.0.0.1:3000 user@server opens local port 8790 and forwards it to port 3000 as seen from the SSH server. Then open http://127.0.0.1:8790 locally.
- -N avoids starting a remote shell.
- The first 127.0.0.1 restricts access to your machine.
- The target host is resolved from the SSH server's perspective.
Remote and dynamic forwarding
-R exposes a server-side port that leads back to the client, while -D creates a local SOCKS proxy. Both are useful but require careful bind addresses and sshd policy.
Reliability and diagnostics
Use ExitOnForwardFailure=yes so the client does not appear connected when it failed to open the port. Keepalive detects dead sessions, and an explicit tunnel list makes it easy to stop the correct process.
- Check local port conflicts before starting.
- Show direction, source and destination clearly.
- Do not save passwords in tunnel definitions; use keys and the system credential store.
Secure tunnel definition
- Choose L, R or D deliberately.
- Bind local access to 127.0.0.1.
- Use an SSH key and verify the host key.
- Enable forward-failure detection.
- Stop the tunnel when work is complete.
Put it into practice
Manage tunnels in N3XShell
Save hosts and tunnels, start them with one click and monitor them beside SSH terminal and SFTP.
Manage tunnels in N3XShellFrequently asked questions
How do I open a Docker dashboard bound to server localhost?
For example, run ssh -N -L 127.0.0.1:8790:127.0.0.1:3000 user@server and open http://127.0.0.1:8790 locally.
Does the tunnel encrypt traffic?
Traffic between the client and SSH server is encrypted. The segment from the SSH server to the target depends on the selected host and network.
Why will the local port not start?
It may already be occupied, reserved or blocked. Inspect the listening process and choose another local port.
