SSH tunnels
An SSH connection can carry other connections inside it. This is called port forwarding, or a tunnel. By the end of this lesson you can reach a service that only a server can see, let a server reach a service on your device, and keep both private.
Why tunnel
Lesson 1 showed that a service listening on 127.0.0.1 can only be reached from the same machine. That is good for safety, and awkward when you want to use it from your laptop or phone. Opening it to the network would make it reachable by everyone.
A tunnel gives you a third option: the service stays private, and you reach it through the SSH connection you already have, encrypted and with your SSH sign-in as the only door.
There are three kinds:
| Kind | ssh flag | Who listens | Typical use |
|---|---|---|---|
| Local forward | -L | Your device | Reach a database or web page that only the server can reach |
| Remote forward | -R | The server | Let the server reach something running on your device |
| Dynamic (SOCKS5) | -D | Your device | Browse through the server's network |
Local forward: bring a far service here
The server 192.168.1.20 runs PostgreSQL on 127.0.0.1:5432, so nobody else on the network can reach it. You want a database tool on your laptop to use it.
ssh -N -L 15432:localhost:5432 maya@192.168.1.20Read -L 15432:localhost:5432 as "listen on my port 15432; send each connection to localhost:5432, as seen from the server". -N means "no remote command, only the tunnel". The command keeps running until you press Ctrl + C.
Laptop Server 192.168.1.20
┌──────────────────────┐ ┌──────────────────────────┐
│ database tool │ │ │
│ connects to │ SSH, port 22 │ sshd ──► 127.0.0.1:5432 │
│ localhost:15432 ───┼═══════════════════┼──► PostgreSQL │
│ (ssh listens here) │ everything inside│ │
└──────────────────────┘ encrypted └──────────────────────────┘The most confusing part is the word localhost in the middle. It is looked up on the server, so it means the server itself. You can put any address the server can reach there instead. For example, to open your router's settings page through a home server:
ssh -N -L 8081:192.168.1.1:80 maya@192.168.1.20Then browse to http://localhost:8081 on your laptop.
In SecureShell Go, the same local forward is a saved tunnel:
ssh -L part | SecureShell Go field |
|---|---|
maya@192.168.1.20 | Carried by: the saved host |
15432 | Local port |
localhost | Destination host |
5432 | Destination port |
Choose Local forward as the Type, save it, and switch it on in the Tunnels list. See Forward ports with tunnels. CrossShell calls this a Local (-L) forward; see Forward a port.
Remote forward: let the server reach you
You are building a web app on your laptop on port 3000, and want a program on the server to call it.
ssh -N -R 9000:localhost:3000 maya@192.168.1.20Read -R 9000:localhost:3000 as "the server listens on its port 9000; send each connection back to localhost:3000, as seen from my laptop".
Laptop Server 192.168.1.20
┌──────────────────────┐ ┌──────────────────────────┐
│ web app on │ │ program on the server │
│ localhost:3000 ◄─────┼═══════════════════┼─── calls localhost:9000 │
│ │ SSH, port 22 │ (sshd listens here) │
└──────────────────────┘ └──────────────────────────┘By default the server listens on its own loopback address only, so only programs on the server can use port 9000. In SecureShell Go, a Remote forward has a Port on the server, an optional Bind address on the server, and the Address on this device and Port on this device that connections are handed to.
Dynamic forward: a SOCKS proxy
A SOCKS5 proxy is a relay that programs can ask to open connections for them. -D makes ssh act as one on your device, and every connection is opened by the server instead:
ssh -N -D 1080 maya@192.168.1.20Point a browser's proxy setting at SOCKS5 127.0.0.1 port 1080, or tell one command to use it:
curl --socks5-hostname 127.0.0.1:1080 http://192.168.1.1/The router's page loads as if you were at home, because the server, which is at home, made the request. --socks5-hostname also sends the name lookup through the server, so names on the far network work.
Only programs that are set to use the proxy go through it. It is not a VPN for the whole device. In SecureShell Go this is the Dynamic (SOCKS5) type.
Who can use your tunnel
A tunnel is a listening port, so lesson 1's rule applies: the address it listens on decides who can use it.
| Command | Listens on | Who can use it |
|---|---|---|
ssh -L 15432:localhost:5432 … | 127.0.0.1:15432 (the default) | Only programs on your device |
ssh -L 0.0.0.0:15432:localhost:5432 … | Every interface | Anyone who can reach your device |
The second form opens the database to everyone on your Wi-Fi, and the tunnel has no password of its own: whoever connects to it uses your SSH sign-in. SecureShell Go listens on 127.0.0.1 unless you turn on Allow other devices to use it, and warns you when you do.
For remote forwards, the server decides. Its GatewayPorts setting is off by default, so the server listens on loopback only, even if you ask for more.
Why not open a port on the router
To reach a home computer from outside, a common tip is to set up port forwarding on the router: "send everything that arrives on port 22 to 192.168.1.20". This is not the same as an SSH tunnel. It puts that computer's SSH server in front of the whole internet, where automated scanners soon find it and start guessing passwords.
Safer ways to reach home from outside:
- A VPN (virtual private network) such as WireGuard, which makes your phone or laptop part of your home LAN wherever it is. CrossShell's guide gives the same advice for using it across the internet.
- Do it when you are home. Many tasks can wait.
If you do expose SSH to the internet, lesson 5's keys-only settings stop being optional.
SSH tunnels and public tunnels
Mock Studio can also start a "tunnel", through cloudflared or ngrok. The word is the same; the idea is close to the opposite.
| SSH tunnel | Public tunnel (Mock Studio's Public internet (tunnel)) | |
|---|---|---|
| Who can use it | Only someone who can sign in with SSH (and, by default, only on their own device) | Anyone who has the address |
| Address | localhost and a port on your device or the server | A random public https:// address |
| Needs | An SSH server you can sign in to | cloudflared or ngrok installed |
| Use it for | Reaching your own private services | Letting something on the internet, such as a webhook sender, reach your mock |
A public tunnel puts your mock on the open internet for as long as it runs. Stop it as soon as you are done. See Share on LAN or the internet.
Stay safe
- Keep tunnels on
127.0.0.1. Leave Allow other devices to use it off, and never turn it on on public Wi-Fi. - Stop tunnels when you are finished. In SecureShell Go, Stop all stops every running tunnel.
- Do not open router ports to reach home; use a VPN.
- Only tunnel into networks you are allowed to use. A tunnel through a work server into its network can break your organisation's rules even when it works.
- Treat a public tunnel address like a password and keep secrets out of what it serves.
Check yourself
Question 1 of 6
You run this command on your laptop. Where does the database have to be for it to work?
ssh -N -L 15432:localhost:5432 maya@192.168.1.20What you learned
-Llistens on your device and opens connections from the server;-Ris the reverse;-Dis a SOCKS proxy.- In
-L 15432:localhost:5432,localhostis the server itself. - Tunnels listen on
127.0.0.1by default; listening on every interface opens them to the network with no extra password. - A router port forward exposes a computer to the internet; a VPN is the safer way in.
- An SSH tunnel needs an SSH sign-in; a public tunnel is open to anyone with the address.
Next steps
- Secure your SSH server
- Forward ports with tunnels in SecureShell Go
- Forward a port in CrossShell