SSH (Secure Shell) is the lifeline of Linux system administration. It's how you access remote servers, transfer files securely, create encrypted tunnels, and automate tasks across your infrastructure. Whether you're managing a single VPS or hundreds of production servers, mastering SSH is essential. This guide takes you from SSH basics to advanced techniques used by senior DevOps engineers.
📥 Free Cheat Sheet
Download our SSH Commands & Config Cheat Sheet PDF — key management, tunneling, and hardening settings at a glance.
SSH Key Authentication
Key-based authentication is more secure than passwords and enables passwordless automation:
Generating Keys
# Generate Ed25519 key (recommended, most secure)
ssh-keygen -t ed25519 -C "admin@myserver.com"
# Generate RSA key (wider compatibility)
ssh-keygen -t rsa -b 4096 -C "admin@myserver.com"
# Generate with specific filename
ssh-keygen -t ed25519 -f ~/.ssh/work_key -C "work server"
# Generate without passphrase (for automation only!)
ssh-keygen -t ed25519 -f ~/.ssh/automation_key -N ""
Deploying Public Keys
# Copy key to remote server (easiest method)
ssh-copy-id user@server
# Copy specific key
ssh-copy-id -i ~/.ssh/work_key.pub user@server
# Manual method
cat ~/.ssh/id_ed25519.pub | ssh user@server 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
# Set correct permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
SSH Config File
The SSH config file (~/.ssh/config) transforms your SSH workflow by creating named shortcuts with pre-configured settings:
# ~/.ssh/config
# Default settings for all hosts
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes
IdentitiesOnly yes
# Production web server
Host prod-web
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/prod_key
# Staging server
Host staging
HostName 192.168.1.50
User admin
IdentityFile ~/.ssh/staging_key
# Database server (via jump host)
Host prod-db
HostName 10.0.1.50
User dbadmin
IdentityFile ~/.ssh/prod_key
ProxyJump prod-web
# Multiple servers with wildcard
Host dev-*
User developer
IdentityFile ~/.ssh/dev_key
ForwardAgent yes
Host dev-app
HostName 10.0.2.10
Host dev-api
HostName 10.0.2.20
Now you can simply type ssh prod-web instead of ssh -p 2222 -i ~/.ssh/prod_key deploy@203.0.113.10.
SSH Tunneling and Port Forwarding
Local Port Forwarding
Access a remote service through your local machine. Perfect for accessing databases or internal web services behind firewalls:
# Access remote PostgreSQL (port 5432) on localhost:5432
ssh -L 5432:localhost:5432 user@db-server
# Access remote web app on localhost:8080
ssh -L 8080:localhost:3000 user@app-server
# Access a service on the remote network
ssh -L 3306:database-host:3306 user@jump-host
# Background tunnel (runs in background)
ssh -fNL 5432:localhost:5432 user@db-server
Remote Port Forwarding
Expose your local service to the remote server. Useful for demos or debugging:
# Make your local port 3000 accessible on remote port 8080
ssh -R 8080:localhost:3000 user@remote-server
# Background reverse tunnel
ssh -fNR 8080:localhost:3000 user@remote-server
Dynamic Port Forwarding (SOCKS Proxy)
# Create SOCKS proxy on localhost:1080
ssh -D 1080 user@proxy-server
# Background SOCKS proxy
ssh -fND 1080 user@proxy-server
# Use with curl
curl --socks5 localhost:1080 https://example.com
Jump Hosts (Bastion Hosts)
# ProxyJump (SSH 7.3+)
ssh -J jump-host user@internal-server
# Multiple jumps
ssh -J jump1,jump2 user@internal-server
# In SSH config
Host internal-server
HostName 10.0.1.50
User admin
ProxyJump bastion-host
# Older method with ProxyCommand
Host internal-server
HostName 10.0.1.50
ProxyCommand ssh -W %h:%p bastion-host
SCP and SFTP — Secure File Transfer
# Copy file to remote
scp file.txt user@server:/remote/path/
# Copy file from remote
scp user@server:/remote/file.txt ./local/
# Copy directory recursively
scp -r /local/dir/ user@server:/remote/
# Copy with custom port
scp -P 2222 file.txt user@server:/path/
# SFTP interactive session
sftp user@server
# Commands: ls, cd, get, put, mkdir, rm
# SFTP batch mode
sftp -b commands.txt user@server
SSH Agent and Key Management
# Start SSH agent
eval $(ssh-agent -s)
# Add key to agent
ssh-add ~/.ssh/id_ed25519
# Add key with timeout (auto-remove after 1 hour)
ssh-add -t 3600 ~/.ssh/id_ed25519
# List keys in agent
ssh-add -l
# Remove all keys from agent
ssh-add -D
# Forward agent to remote (use with caution!)
ssh -A user@server
SSH Security Hardening
Securing your SSH server is critical. Edit /etc/ssh/sshd_config:
# Disable root login
PermitRootLogin no
# Disable password authentication (key-only)
PasswordAuthentication no
PubkeyAuthentication yes
# Change default port
Port 2222
# Limit SSH to specific users
AllowUsers admin deploy
# Or by group:
AllowGroups sshusers
# Disable empty passwords
PermitEmptyPasswords no
# Set login grace time
LoginGraceTime 30
# Limit authentication attempts
MaxAuthTries 3
# Disable X11 forwarding (if not needed)
X11Forwarding no
# Disable TCP forwarding (if not needed)
AllowTcpForwarding no
# Use strong ciphers only
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
# Idle timeout (disconnect after 10 min idle)
ClientAliveInterval 300
ClientAliveCountMax 2
# After changes, test config and restart
sudo sshd -t
sudo systemctl restart sshd
Additional Security Measures
# Install fail2ban for brute force protection
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
# Configure fail2ban for SSH
# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 2222
maxretry = 3
bantime = 3600
findtime = 600
# Two-factor authentication with Google Authenticator
sudo apt install libpam-google-authenticator
google-authenticator # Run as user
# Edit /etc/pam.d/sshd to enable
SSH Multiplexing — Faster Connections
# ~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
# Create sockets directory
mkdir -p ~/.ssh/sockets
# Benefits:
# - First connection authenticates normally
# - Subsequent connections reuse the existing channel
# - Much faster for repeated connections (scp, rsync, etc.)
Advanced SSH Tricks
# Run remote command without interactive shell
ssh user@server 'df -h && free -h'
# Pipe commands through SSH
cat backup.sql | ssh user@server 'psql dbname'
ssh user@server 'pg_dump dbname' > local-backup.sql
# Mount remote filesystem with sshfs
sudo apt install sshfs
sshfs user@server:/remote/path /local/mount
# Unmount
fusermount -u /local/mount
# Copy your public key + shell in one command
ssh user@server 'cat >> ~/.ssh/authorized_keys' < ~/.ssh/id_ed25519.pub
# SSH escape sequences (while connected)
# ~. Disconnect
# ~^Z Suspend SSH
# ~C Open command line (for adding port forwards)
# ~? List available escapes
📚 Master Remote Administration
- Linux Administration Fundamentals — Complete foundation including SSH
- Linux Security Auditing — SSH security in depth
- Linux Networking Fundamentals — Network security and tunneling
- Linux System Administration Masterclass — Enterprise server management