SSH keys provide passwordless, cryptographically secure authentication for remote servers, Git hosting, and automated deployments. Ed25519 keys are the current recommended default — they are faster, smaller, and more secure than RSA. This guide covers key generation, agent management, the SSH config file, tunneling, and security hardening.
How Do You Generate an SSH Key?
Use ssh-keygen with the Ed25519 algorithm. It produces a 256-bit key that is more secure than a 3072-bit RSA key and generates/verifies signatures significantly faster.
# Generate a new Ed25519 key with a comment (usually your email)
ssh-keygen -t ed25519 -C "dev@example.com"
# You'll be prompted for:
# File: ~/.ssh/id_ed25519 (default, press Enter)
# Passphrase: use a strong passphrase (recommended)
# Result: two files
# ~/.ssh/id_ed25519 ← private key (never share this)
# ~/.ssh/id_ed25519.pub ← public key (copy to servers)
# If you need RSA for legacy systems (4096-bit minimum)
ssh-keygen -t rsa -b 4096 -C "dev@example.com"Why Ed25519? Ed25519 keys are 68 characters in the public key file vs 500+ for RSA-4096. They use the Curve25519 elliptic curve and are resistant to several classes of side-channel attacks that affect NIST curves. OpenSSH has supported Ed25519 since version 6.5 (2014).
How Do You Copy Your Key to a Server?
Use ssh-copy-id to install your public key on a remote server. This appends the key to ~/.ssh/authorized_keys on the server with correct permissions.
# Automatic method (recommended)
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server.example.com
# Manual method (when ssh-copy-id is unavailable)
cat ~/.ssh/id_ed25519.pub | ssh user@server.example.com \
'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
# For GitHub/GitLab — paste the public key in the web UI
cat ~/.ssh/id_ed25519.pub
# Copy the output and add it in Settings → SSH KeysHow Does ssh-agent Work?
The SSH agent holds decrypted private keys in memory so you only enter your passphrase once per session. It forwards keys to remote servers when configured, enabling multi-hop connections without copying private keys.
# Start the agent (usually automatic on modern systems)
eval "$(ssh-agent -s)"
# Add your key (prompts for passphrase once)
ssh-add ~/.ssh/id_ed25519
# List loaded keys
ssh-add -l
# On macOS — store passphrase in Keychain
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
# Remove all keys from agent
ssh-add -D
# Set key lifetime (auto-remove after 8 hours)
ssh-add -t 8h ~/.ssh/id_ed25519How Should You Configure ~/.ssh/config?
The SSH config file lets you define aliases, set per-host options, and avoid repetitive command-line flags. It is read top-to-bottom — the first matching Host block wins for each directive.
# Global defaults
Host *
AddKeysToAgent yes
IdentitiesOnly yes
ServerAliveInterval 60
ServerAliveCountMax 3
# Production server
Host prod
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519_prod
ForwardAgent no
# Staging via bastion/jump host
Host staging
HostName 10.0.1.50
User deploy
ProxyJump bastion
Host bastion
HostName bastion.example.com
User jump
IdentityFile ~/.ssh/id_ed25519
ForwardAgent no
# GitHub — use a specific key
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github
# Wildcard — all dev servers
Host dev-*
User developer
IdentityFile ~/.ssh/id_ed25519_devHow Do SSH Tunnels and Port Forwarding Work?
SSH tunnels encrypt traffic between your machine and a remote server, letting you access services behind firewalls or on private networks.
# Local port forwarding — access remote service on localhost
# Access remote PostgreSQL (port 5432) via localhost:15432
ssh -L 15432:localhost:5432 user@db-server.example.com
# Remote port forwarding — expose local service to remote network
# Make local port 3000 available on remote server's port 8080
ssh -R 8080:localhost:3000 user@remote.example.com
# Dynamic port forwarding — SOCKS5 proxy
# Route browser traffic through the SSH server
ssh -D 1080 user@proxy.example.com
# Then configure browser to use SOCKS5 proxy at localhost:1080
# Tunnel in background without a shell
ssh -fNL 15432:localhost:5432 user@db-server.example.com
# -f = background after auth, -N = no remote commandWhat Is ProxyJump and How Do You Use It?
ProxyJump (or -J) lets you connect through an intermediate bastion host without manually chaining SSH sessions. It replaces the older, more complex ProxyCommand.
# Single jump host
ssh -J bastion.example.com user@internal-server
# Multiple jump hosts (chained)
ssh -J bastion1.example.com,bastion2.internal user@final-target
# Equivalent config file entry
# Host internal
# HostName 10.0.1.50
# User deploy
# ProxyJump bastion.example.com
# Copy files through a jump host
scp -J bastion.example.com localfile.txt user@internal:/tmp/What Are the SSH Security Best Practices?
Harden your SSH setup to reduce attack surface. Most breaches involve weak passwords, exposed keys, or default configurations.
# Disable password authentication entirely
PasswordAuthentication no
ChallengeResponseAuthentication no
# Disable root login
PermitRootLogin no
# Use only Ed25519 host keys
HostKey /etc/ssh/ssh_host_ed25519_key
# Restrict to specific users/groups
AllowUsers deploy admin
# Or: AllowGroups ssh-users
# Change default port (reduces noise, not a security measure)
Port 2222
# Limit authentication attempts
MaxAuthTries 3
# Disable agent and X11 forwarding unless needed
AllowAgentForwarding no
X11Forwarding no
# Idle timeout
ClientAliveInterval 300
ClientAliveCountMax 2Critical: Never add private keys to Git repositories, Docker images, or CI logs. Use ssh-agent forwarding or deploy keys with read-only access instead. Set file permissions to chmod 600 ~/.ssh/id_ed25519 and chmod 700 ~/.ssh/.
Key Takeaways
- • Use Ed25519 keys by default — they are faster, smaller, and more secure than RSA
- • Always set a passphrase on your private key and use ssh-agent to cache it
- • Configure
~/.ssh/configwith host aliases, identity files, and jump hosts - • Use ProxyJump for bastion hosts instead of the older ProxyCommand
- • Local port forwarding (
-L) accesses remote services; remote forwarding (-R) exposes local services - • Disable password auth and root login on servers — key-only authentication is the standard
- • Private key permissions must be 600; the ~/.ssh directory must be 700