Skip to content

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:

Kindssh flagWho listensTypical use
Local forward-LYour deviceReach a database or web page that only the server can reach
Remote forward-RThe serverLet the server reach something running on your device
Dynamic (SOCKS5)-DYour deviceBrowse 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.

bash
ssh -N -L 15432:localhost:5432 maya@192.168.1.20

Read -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.

text
 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:

bash
ssh -N -L 8081:192.168.1.1:80 maya@192.168.1.20

Then browse to http://localhost:8081 on your laptop.

In SecureShell Go, the same local forward is a saved tunnel:

ssh -L partSecureShell Go field
maya@192.168.1.20Carried by: the saved host
15432Local port
localhostDestination host
5432Destination 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.

bash
ssh -N -R 9000:localhost:3000 maya@192.168.1.20

Read -R 9000:localhost:3000 as "the server listens on its port 9000; send each connection back to localhost:3000, as seen from my laptop".

text
 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:

bash
ssh -N -D 1080 maya@192.168.1.20

Point a browser's proxy setting at SOCKS5 127.0.0.1 port 1080, or tell one command to use it:

bash
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.

CommandListens onWho 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 interfaceAnyone 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 tunnelPublic tunnel (Mock Studio's Public internet (tunnel))
Who can use itOnly someone who can sign in with SSH (and, by default, only on their own device)Anyone who has the address
Addresslocalhost and a port on your device or the serverA random public https:// address
NeedsAn SSH server you can sign in tocloudflared or ngrok installed
Use it forReaching your own private servicesLetting 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 ​

QuizSSH tunnels

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.20
Score: 0

What you learned ​

  • -L listens on your device and opens connections from the server; -R is the reverse; -D is a SOCKS proxy.
  • In -L 15432:localhost:5432, localhost is the server itself.
  • Tunnels listen on 127.0.0.1 by 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 ​