SSH Cheatsheet
Basic Connection
| Command | Description |
|---|---|
ssh user@host | Connect to remote host |
ssh -p 2222 user@host | Connect on custom port |
ssh -i ~/.ssh/key.pem user@host | Connect with specific key |
ssh -v user@host | Verbose mode (debug) |
ssh -vvv user@host | Extra verbose |
Authentication
Key-Based Auth
# Generate key pair
ssh-keygen -t ed25519 -C "comment"
ssh-keygen -t rsa -b 4096 -C "comment"
# Copy public key to server
ssh-copy-id user@host
ssh-copy-id -i ~/.ssh/key.pub user@host
# Manual copy
cat ~/.ssh/id_ed25519.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
Key Permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/config
SSH Config File
Location: ~/.ssh/config
Host myserver
HostName 192.168.1.100
User admin
Port 22
IdentityFile ~/.ssh/myserver_key
Host jumpbox
HostName jump.example.com
User deployer
IdentityFile ~/.ssh/jump_key
Host internal
HostName 10.0.0.50
User admin
ProxyJump jumpbox
Config Options
| Option | Description |
|---|---|
HostName | Actual hostname/IP |
User | Default username |
Port | SSH port |
IdentityFile | Path to private key |
ProxyJump | Jump host for tunneling |
ForwardAgent | Forward SSH agent (yes/no) |
LocalForward | Persistent local tunnel |
DynamicForward | Persistent SOCKS proxy |
Port Forwarding / Tunneling
Local Port Forwarding (-L)
Forward a local port to a remote destination through the SSH server.
ssh -L [local_addr:]local_port:remote_host:remote_port user@ssh_server
Use case: Access a service on a remote network that’s not directly reachable.
# Forward local port 8080 to remote host's port 80
ssh -L 8080:webserver.internal:80 user@jumphost
# Access via: http://localhost:8080
PostgreSQL Example (Remote DB on localhost)
Scenario: PostgreSQL on dbserver only listens on 127.0.0.1:5432. You need to connect from your workstation.
# Create tunnel
ssh -L 5432:localhost:5432 user@dbserver
# Now connect locally
psql -h localhost -p 5432 -U dbuser -d mydb
Or use a different local port to avoid conflicts:
# Forward local 15432 to remote's localhost:5432
ssh -L 15432:localhost:5432 user@dbserver
# Connect via the tunnel
psql -h localhost -p 15432 -U dbuser -d mydb
# Or with connection string
psql "postgresql://dbuser:password@localhost:15432/mydb"
Background tunnel (no shell):
ssh -fNL 15432:localhost:5432 user@dbserver
# -f: Background after auth
# -N: No remote command (tunnel only)
# -L: Local forward
Multiple Forwards
ssh -L 5432:localhost:5432 -L 6379:localhost:6379 user@server
Remote Port Forwarding (-R)
Expose a local service to the remote network.
ssh -R [remote_addr:]remote_port:local_host:local_port user@ssh_server
Use case: Make your local dev server accessible from the remote server.
# Expose local port 3000 on remote server's port 8080
ssh -R 8080:localhost:3000 user@remote
# On remote: curl localhost:8080 hits your local :3000
Dynamic Port Forwarding (-D) - SOCKS Proxy
Create a SOCKS proxy that routes all traffic through the SSH server.
ssh -D [local_addr:]local_port user@ssh_server
Use case: Browse the web or access multiple services as if you were on the remote network.
# Create SOCKS5 proxy on localhost:1080
ssh -D 1080 user@remote
# Configure browser/apps to use SOCKS5 proxy: localhost:1080
Using the SOCKS Proxy
curl:
curl --socks5 localhost:1080 http://internal.site.local
proxychains:
# /etc/proxychains.conf
socks5 127.0.0.1 1080
# Run commands through proxy
proxychains psql -h db.internal -U admin -d mydb
proxychains nmap -sT 10.0.0.0/24
Browser: Configure SOCKS5 proxy in Firefox/Chrome settings or use FoxyProxy.
PostgreSQL via SOCKS Proxy
# Start SOCKS proxy
ssh -D 1080 user@jumphost
# Use proxychains
proxychains psql -h db.internal.local -p 5432 -U dbuser -d mydb
Tunnel Comparison
| Type | Flag | Direction | Use Case |
|---|---|---|---|
| Local | -L | Local → Remote | Access remote service locally |
| Remote | -R | Remote → Local | Expose local service remotely |
| Dynamic | -D | SOCKS Proxy | Route all traffic through SSH |
Tunnel Options
| Flag | Description |
|---|---|
-f | Background after authentication |
-N | No remote command (tunnel only) |
-T | Disable pseudo-terminal allocation |
-g | Allow remote hosts to connect to forwarded ports |
Common Tunnel Command
# Background tunnel, no shell
ssh -fNT -L 5432:localhost:5432 user@server
# Check tunnel is running
ps aux | grep ssh
lsof -i :5432
Jump Hosts / Bastion
ProxyJump (Modern)
ssh -J jumphost user@internal
# Multiple jumps
ssh -J jump1,jump2 user@internal
ProxyCommand (Legacy)
ssh -o ProxyCommand="ssh -W %h:%p jumphost" user@internal
Config File
Host internal
HostName 10.0.0.50
User admin
ProxyJump jumphost
SSH Agent
# Start agent
eval $(ssh-agent)
# Add key
ssh-add ~/.ssh/id_ed25519
# Add with timeout (1 hour)
ssh-add -t 3600 ~/.ssh/id_ed25519
# List keys
ssh-add -l
# Remove all keys
ssh-add -D
Agent Forwarding
ssh -A user@host
Warning: Agent forwarding can be a security risk on untrusted hosts.
File Transfer
SCP
# Upload
scp file.txt user@host:/path/
# Download
scp user@host:/path/file.txt ./
# Recursive
scp -r folder/ user@host:/path/
# With custom port
scp -P 2222 file.txt user@host:/path/
SFTP
sftp user@host
sftp> put localfile
sftp> get remotefile
sftp> ls
sftp> cd /path
sftp> exit
Rsync over SSH
rsync -avz -e ssh source/ user@host:/dest/
rsync -avz -e "ssh -p 2222" source/ user@host:/dest/
Escape Sequences
Press ~ after newline:
| Sequence | Action |
|---|---|
~. | Disconnect |
~^Z | Background SSH |
~# | List forwarded connections |
~? | Help |
~C | Open command line (add forwards) |
Add Forward to Running Session
~C
ssh> -L 8080:localhost:80
Security Options
| Option | Description |
|---|---|
-o StrictHostKeyChecking=yes | Reject unknown hosts |
-o UserKnownHostsFile=/dev/null | Don’t save host keys |
-o PasswordAuthentication=no | Force key auth |
-o PubkeyAuthentication=yes | Enable key auth |
Disable Host Key Checking (Testing Only)
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@host
Practical Examples
Access Remote PostgreSQL (localhost only)
# Scenario: PostgreSQL on server only binds to 127.0.0.1:5432
# Option 1: Local forward
ssh -L 5432:127.0.0.1:5432 user@dbserver
psql -h localhost -U postgres -d mydb
# Option 2: Different local port
ssh -fNL 15432:127.0.0.1:5432 user@dbserver
psql -h localhost -p 15432 -U postgres -d mydb
# Option 3: Via jump host
ssh -L 5432:dbserver.internal:5432 user@jumphost
psql -h localhost -U postgres -d mydb
Access Remote Redis
ssh -L 6379:localhost:6379 user@server
redis-cli -h localhost
Browse Internal Network
ssh -D 9050 user@internal-host
# Configure browser SOCKS5: localhost:9050
Tunnel to Multiple Services
ssh -L 5432:localhost:5432 \
-L 6379:localhost:6379 \
-L 8080:webapp.internal:80 \
user@jumphost
Troubleshooting
| Issue | Solution |
|---|---|
| Connection refused | Check SSH service, firewall, port |
| Permission denied | Check key permissions, user, auth method |
| Host key changed | Remove old key: ssh-keygen -R host |
| Tunnel not working | Check if remote port is listening on localhost |
| Broken pipe | Add ServerAliveInterval 60 to config |
Debug Connection
ssh -vvv user@host
Keep Connection Alive
# ~/.ssh/config
Host *
ServerAliveInterval 60
ServerAliveCountMax 3