Most developers use SSH every day but only scratch the surface of what it can do. This guide covers the SSH config file, key management, port forwarding, jump hosts, connection multiplexing, and essential server hardening — techniques that will save you significant time.
The ~/.ssh/config file lets you define aliases and options for SSH connections. Instead of typing ssh -i ~/.ssh/my-key.pem ec2-user@54.123.45.67 every time, you can define a host entry and just type ssh myserver.
# ~/.ssh/config
Host myserver
HostName 54.123.45.67
User ec2-user
IdentityFile ~/.ssh/my-key.pem
Port 22
Host dev-db
HostName 10.0.1.50
User ubuntu
IdentityFile ~/.ssh/dev-key
ProxyJump myserver # Connect through myserver as a jump host
# Apply settings to all hosts
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes
The ServerAliveInterval setting prevents SSH sessions from timing out due to inactivity by sending keepalive packets every 60 seconds.
# Generate a modern Ed25519 key (preferred over RSA)
ssh-keygen -t ed25519 -C "alice@laptop" -f ~/.ssh/id_ed25519
# Generate RSA (if Ed25519 is not supported)
ssh-keygen -t rsa -b 4096 -C "alice@laptop" -f ~/.ssh/id_rsa
# Copy public key to a server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
# Manually append key (same effect as ssh-copy-id)
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
id_ed25519 or id_rsa). Only share the .pub file. Set private key permissions to 600: chmod 600 ~/.ssh/id_ed25519Add your key to the SSH agent so you only need to enter the passphrase once per session:
# Start the agent (usually already running on modern systems)
eval "$(ssh-agent -s)"
# Add your key to the agent
ssh-add ~/.ssh/id_ed25519
# List keys currently loaded in the agent
ssh-add -l
# macOS: persist keys across reboots in Keychain
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
SSH tunneling lets you access services on a remote server as if they were running locally. This is invaluable for accessing databases, admin UIs, and internal services.
# Access a remote PostgreSQL database on your local port 5433
ssh -L 5433:localhost:5432 user@database-server
# Now connect locally:
psql -h localhost -p 5433 -U postgres mydb
# Keep tunnel open without a shell (background mode)
ssh -fNL 5433:localhost:5432 user@database-server
# Create a SOCKS5 proxy through the remote server
ssh -D 8080 user@remote-server
# Then configure your browser to use SOCKS5 proxy at localhost:8080
# All browser traffic will route through the remote server
In secure environments, you often cannot SSH directly to internal servers. A jump host (bastion) is an intermediary. ProxyJump handles the two-hop connection transparently:
# Connect to internal-server through bastion-host in one command
ssh -J user@bastion-host user@internal-server
# Multiple jump hops
ssh -J user@bastion,user@second-hop user@final-destination
# In ~/.ssh/config (cleaner approach)
Host internal
HostName 10.0.1.100
User ubuntu
ProxyJump bastion
Each SSH connection requires a cryptographic handshake. Multiplexing reuses an existing connection for subsequent SSH commands to the same host, making them much faster.
# ~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h:%p
ControlPersist 10m
mkdir -p ~/.ssh/sockets
After the first connection, subsequent connections to the same host are nearly instant. ControlPersist 10m keeps the master connection alive for 10 minutes after all sessions close.
# scp: copy files over SSH
scp file.txt user@server:/home/user/
scp -r local-dir/ user@server:/var/www/
# rsync: efficient sync (only transfers changed data)
rsync -avz --progress local-dir/ user@server:/var/www/app/
# rsync over SSH with custom port
rsync -avz -e "ssh -p 2222" local-dir/ user@server:/var/www/
If you manage SSH servers, apply these settings in /etc/ssh/sshd_config:
# Disable password authentication (require keys)
PasswordAuthentication no
# Disable root login
PermitRootLogin no
# Only allow specific users
AllowUsers alice bob deploy
# Use modern algorithms
KexAlgorithms curve25519-sha256,diffie-hellman-group16-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
# After editing, test config and restart
sshd -t # Test for syntax errors
systemctl restart sshd
fail2ban on any internet-facing SSH server. It automatically bans IP addresses after repeated failed login attempts, dramatically reducing brute-force attack exposure.