The problem
You need to access services behind firewalls, secure unencrypted traffic, or create VPN-like connections.
The solution
# Local port forwarding (access remote service locally)
ssh -L local_port:remote_host:remote_port user@ssh_server
ssh -L 3306:localhost:3306 user@dbserver # Forward MySQL
# Remote port forwarding (expose local service remotely)
ssh -R remote_port:local_host:local_port user@ssh_server
ssh -R 8080:localhost:80 user@jumpserver # Expose web server
# Dynamic port forwarding (SOCKS proxy)
ssh -D local_port user@ssh_server
ssh -D 1080 user@proxy_server # SOCKS proxy on port 1080
# Multiple port forwards
ssh -L 3306:localhost:3306 -L 5432:localhost:5432 user@server
# Forward with specific bind address
ssh -L 127.0.0.1:8080:remote:80 user@server # Only localhost
ssh -L *:8080:remote:80 user@server # All interfaces
# Keep tunnel alive
ssh -o ServerAliveInterval=60 -L ... user@server
# Background tunneling
ssh -f -N -L ... user@server # Fork to background
ssh -f -N -D 1080 user@server # Background SOCKS proxy
# Tunnel through jump host
ssh -J user@jumpserver user@target
ssh -L ... -J user@jumpserver user@target
# Create VPN (tun device)
ssh -w any:any user@server # Requires tun/tap and root
# X11 forwarding (GUI applications)
ssh -X user@server # Forward X11
ssh -Y user@server # Trusted X11 forwarding
# Agent forwarding
ssh -A user@server # Forward SSH agent
# Escape character for managing connections
~? # During SSH session, shows escape chars
~C # Open command line for port forwarding
# Config file setup for recurring tunnels
# ~/.ssh/config:
Host tunnel
HostName ssh.server.com
User myuser
LocalForward 5901 localhost:5900 # VNC
LocalForward 8888 localhost:8888 # Jupyter
ServerAliveInterval 60
ExitOnForwardFailure yesPut it to work
# Access private database
ssh -L 3307:db.internal:3306 user@bastion
# Use as SOCKS proxy for browsing
ssh -D 1080 -C user@vps
# Then configure browser to use SOCKS5 localhost:1080
# Access web server behind firewall
ssh -L 8080:webserver:80 user@gateway
# Now visit http://localhost:8080
# Expose local dev server
ssh -R 8080:localhost:3000 user@vps
# Anyone accessing vps:8080 reaches your localhost:3000
# Complex multi-hop
ssh -L 5432:db:5432 -J user@jump1,user@jump2 user@target
# Persistent tunnel with autossh
autossh -M 0 -o "ServerAliveInterval 30" -L ... user@serverWorth knowing
Local: -L local:remote, Remote: -R remote:local. Use -N for no command execution (just tunnel). -f backgrounds ssh. Use autossh for automatic reconnection. Secure but can be bandwidth-intensive.