1 min read #devops
On this page

SSH Operations Manual

Connection and Configuration

ssh user@host
ssh -p 2222 user@host
ssh -i ~/.ssh/id_ed25519 user@host       # Specify private key

~/.ssh/config is the most important SSH configuration file. Each Host block defines a set of connection parameters:

Host myserver
    HostName 1.2.3.4                     # Actual IP or domain name
    Port 2222                            # Default is 22
    User root                            # Login user
    IdentityFile ~/.ssh/id_ed25519        # Private key path
    ServerAliveInterval 60               # Send keepalive every 60s (prevents NAT/firewall from dropping connection)
    ServerAliveCountMax 3                # Disconnect only after 3 consecutive failures
    # Passwordless login configured → ssh myserver logs in directly

Host github.com
    HostName github.com
    IdentityFile ~/.ssh/id_ed25519_github  # Specify different key when multiple keys exist
    IdentitiesOnly yes                     # Use only this key, do not try other keys in the agent

Host jump-*
    ProxyJump jumphost                    # Connect via jump host

Key Management

# Generate ED25519 key (recommended, faster and more secure than RSA)
ssh-keygen -t ed25519 -C "comment" -f ~/.ssh/id_ed25519

# Copy public key to remote (password → key-based passwordless login)
ssh-copy-id user@host
# Equivalent to: cat ~/.ssh/id_ed25519.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

# List keys in the agent
ssh-add -L
ssh-add ~/.ssh/id_ed25519               # Add key to agent
ssh-add -D                              # Clear agent

# Remove old keys from known_hosts (after reinstalling the system)
ssh-keygen -R hostname
ssh-keygen -R 1.2.3.4

Port Forwarding

# Local forwarding: accessing localhost:8080 = accessing internal:80 reachable from remote
ssh -L 8080:internal:80 user@remote
# Use case: Map remote internal services (e.g., databases) to local ports

# Remote forwarding: accessing remote:3000 = accessing localhost:22
ssh -R 3000:localhost:22 user@remote
# Use case: Expose local SSH to the internet (principle behind homessh)
# Note: By default, it only binds to remote localhost. You need GatewayPorts yes to bind to 0.0.0.0

# Dynamic forwarding (SOCKS5 proxy): Set browser proxy to localhost:1080
ssh -D 1080 user@remote
# Use case: Use SSH server as a proxy (more universal than HTTP CONNECT)

File Transfer

scp file.txt user@host:/path/
scp -r dir/ user@host:/path/
scp user@host:/path/file.txt ./

# rsync supports incremental transfer and resuming
rsync -avz --progress dir/ user@host:/path/
# -a: archive (preserves permissions/timestamps/symlinks)
# -v: verbose
# -z: compress
# --progress: show progress
# Note: dir/ (with slash) = transfer directory contents, dir (without slash) = transfer the directory itself

Troubleshooting

# Verbose debug output (view key exchange, auth process, identify where the issue occurs)
ssh -vvv user@host

# Permission denied (publickey)
# → Check if the local key is password-protected and you forgot to unlock it
# → Check if remote ~/.ssh/authorized_keys contains the correct public key
# → Check remote ~/.ssh permissions: chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys
# → Check remote /etc/ssh/sshd_config: PubkeyAuthentication yes

# Connection refused
# → Is the remote sshd running? systemctl status sshd
# → Is the remote firewall allowing the connection? iptables -L -n -v | grep 22

# Host key verification failed (after reinstalling the system)
ssh-keygen -R hostname

# Connection hangs after establishment (possibly due to slow DNS reverse lookup)
# → Set in remote /etc/ssh/sshd_config: UseDNS no