Chapter 6

Tunnels & Port Forwarding

Local -L, remote -R, accessing private DBs.

Learning objectives

  • Create local, remote, and dynamic SSH tunnels
  • Access internal services (Proxmox, PostgreSQL) safely through SSH
  • Understand security implications of each tunnel type

Port forwarding overview

SSH can carry other TCP traffic inside its encrypted session. Workshop Co. uses tunnels so Marcus administers internal services without publishing them on the internet.

TypeFlagDirectionExample use
Local forward-LLocal port → remote host:portBrowser to Proxmox UI
Remote forward-RRemote port → local host:portExpose dev app temporarily
Dynamic-DSOCKS proxyBrowse through bastion network

Local forward — Proxmox web UI

# Marcus laptop — forward local 8006 to Proxmox on private LAN
ssh -L 8006:192.168.10.2:8006 marcus@bastion.workshopco.ca

# Browser: https://127.0.0.1:8006
# Traffic path: laptop:8006 → SSH → bastion → 192.168.10.2:8006

Same effect as LocalForward 8006 127.0.0.1:8006 in config when Proxmox listens on localhost only from bastion's perspective — adjust target IP accordingly.

Local forward — PostgreSQL admin

Marcus uses TablePlus from home to inspect booking DB — never expose 5432 on the router:

ssh -L 15432:10.20.0.5:5432 workshop-db

# TablePlus connects to localhost:15432, user deploy, db workshop_bookings
Bind address

-L 127.0.0.1:15432:... listens only on laptop localhost. Omitting the bind address can expose the tunnel to your LAN — specify 127.0.0.1 for admin tools.

Remote forward — caution

# On Marcus laptop — expose local dev server to bastion's port 8080
ssh -R 8080:127.0.0.1:3000 marcus@bastion.workshopco.ca

Anyone who can reach bastion:8080 hits Marcus's local app. Workshop Co. disables GatewayPorts on bastion and avoids remote forwards unless debugging with time-limited firewall rules.

Dynamic SOCKS proxy

ssh -D 1080 marcus@bastion.workshopco.ca
# Configure browser SOCKS5 → 127.0.0.1:1080

Useful to reach internal-only HTTP sites (staging dashboard) as if Marcus were on the workshop LAN. Do not use as general VPN replacement without understanding DNS leaks.

Worked example — one-shot tunnel without shell

ssh -N -L 15432:10.20.0.5:5432 workshop-db

-N = no remote command, tunnel only. Marcus runs this in a tmux pane while working.

Try it yourself

Write the command to locally forward port 9080 to Nextcloud on VM 130 at 10.20.0.15:80 through the bastion jump config alias workshop-files.

Answer
ssh -N -L 127.0.0.1:9080:10.20.0.15:80 workshop-files

Check your understanding

  1. Local vs remote forward — which exposes a service from your laptop to the remote network?
  2. Why bind PostgreSQL tunnel to 127.0.0.1?
Answers
  1. Remote forward (-R) — remote listeners reach back to your local machine.
  2. Prevents other devices on your home Wi-Fi from using your DB tunnel without your knowledge.