Command linehardBash

SSH Tunneling and Port Forwarding

Create secure tunnels for accessing services, bypassing firewalls, or encrypting traffic.

01

The problem

You need to access services behind firewalls, secure unencrypted traffic, or create VPN-like connections.

02

The solution

Bash
# 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 yes

03

Put it to work

Example
# 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@server

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