SSH Tunneling Guide
Tunnel Types Overview
| Type | Flag | Use Case |
|---|---|---|
| Local Forwarding | -L | Access remote DB/service locally |
| Remote Forwarding | -R | Expose local service to internet |
| Dynamic (SOCKS) | -D | Full SOCKS proxy via SSH |
Local Port Forwarding
# Access remote PostgreSQL locally at localhost:5432 ssh -L 5432:localhost:5432 user@remote-server # Access service on private network via jump host ssh -L 3306:db.internal:3306 user@bastion-host # Keep connection alive (background) ssh -L 5432:localhost:5432 -N -f user@remote-server # -N = no command, -f = background # Now connect: psql -h localhost -p 5432 -U dbuser mydb
Remote Port Forwarding
# Expose local web server port 3000 on remote server port 8080 # People visiting remote:8080 โ your localhost:3000 ssh -R 8080:localhost:3000 user@remote-server # For public access, add in /etc/ssh/sshd_config on remote: # GatewayPorts yes
Jump Host (ProxyJump)
# Connect to private server via bastion
ssh -J user@bastion user@private-server
# ~/.ssh/config (recommended)
Host private-server
HostName 10.0.0.5
User deploy
ProxyJump bastion
Host bastion
HostName bastion.example.com
User admin
IdentityFile ~/.ssh/bastion_key
# Now just: ssh private-server
Dynamic SOCKS5 Proxy
# Create SOCKS5 proxy on local port 1080 ssh -D 1080 -N -f user@remote-server # Use with curl curl --socks5 localhost:1080 https://internal.site # Use with Chrome (proxy all traffic) google-chrome --proxy-server="socks5://localhost:1080"
SSH Config Hardening
# /etc/ssh/sshd_config best practices PermitRootLogin no PasswordAuthentication no # Keys only PubkeyAuthentication yes X11Forwarding no AllowTcpForwarding yes # required for tunnels MaxAuthTries 3 ClientAliveInterval 300 ClientAliveCountMax 2