SSH Keys — Setup, Management, and Security Best Practices 2026

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Introduction

Why This Matters

Passwords are the weakest link in server authentication — they can be brute-forced, phished, or leaked in data breaches. SSH keys use asymmetric cryptography: the private key never leaves your machine, while the public key is freely distributed to servers. Even if a server is compromised, an attacker cannot derive your private key from the public key stored there.

For DevOps workflows — running Ansible playbooks, deploying via CI/CD, accessing production servers — SSH keys are the foundation of secure, automated access.

Generating SSH Keys

Use Ed25519, the modern standard. It is faster, more secure, and produces shorter keys than RSA:

# Generate an Ed25519 key pair
ssh-keygen -t ed25519 -C "your-email@example.com" -f ~/.ssh/id_ed25519
 
# The -C flag adds a comment (usually email) to identify the key
# The -f flag specifies the output filename
 
# For systems that do not yet support Ed25519, use RSA 4096
ssh-keygen -t rsa -b 4096 -C "your-email@example.com" -f ~/.ssh/id_rsa_legacy

This creates two files:

  • ~/.ssh/id_ed25519 — your private key (never share this)
  • ~/.ssh/id_ed25519.pub — your public key (copy this to servers)

Always set a strong passphrase when prompted. The passphrase encrypts the private key on disk, so even if your laptop is stolen, the key cannot be used without the passphrase.

Setting Correct Permissions

SSH is strict about permissions. If they are too permissive, SSH refuses to use the key:

# Secure the .ssh directory
chmod 700 ~/.ssh
 
# Secure the private key (owner read/write only)
chmod 600 ~/.ssh/id_ed25519
 
# Public key can be world-readable
chmod 644 ~/.ssh/id_ed25519.pub
 
# Authorized keys file
chmod 600 ~/.ssh/authorized_keys

Configuring the SSH Config File

The ~/.ssh/config file lets you define connection profiles so ssh production works instead of typing ssh -i ~/.ssh/prod_key deployuser@10.0.1.5 -p 2222:

# ~/.ssh/config
 
Host production
  HostName prod.example.com
  User deployuser
  IdentityFile ~/.ssh/prod_key
  Port 22
  ForwardAgent no
 
Host staging
  HostName staging.example.com
  User devuser
  IdentityFile ~/.ssh/staging_key
  Port 22
 
Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_github
  AddKeysToAgent yes
 
# Secure defaults for all hosts
Host *
  ServerAliveInterval 60
  ServerAliveCountMax 3
  PasswordAuthentication no
  AddKeysToAgent yes

The wildcard Host * block applies secure defaults to all connections — disabling password authentication and enabling keep-alives to prevent dropped connections.

Using SSH Agent to Cache Passphrases

Typing your passphrase on every SSH command is impractical. The SSH agent caches decrypted keys in memory for the session:

# Start the agent (usually automatic in modern systems)
eval "$(ssh-agent -s)"
 
# Add your key (prompts for passphrase once)
ssh-add ~/.ssh/id_ed25519
 
# List cached keys
ssh-add -l
 
# Remove all keys from agent
ssh-add -D

On macOS, keys added to the agent persist across reboots via the system keychain when AddKeysToAgent yes and UseKeychain yes are set in ~/.ssh/config.

Copying Public Keys to Servers

The ssh-copy-id command appends your public key to a server's ~/.ssh/authorized_keys file:

# Copy default public key to a server
ssh-copy-id user@server.example.com
 
# Copy a specific key
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server.example.com
 
# Manual alternative (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"

Hardening SSH Server Configuration

On servers you control, lock down /etc/ssh/sshd_config to reduce the attack surface:

# /etc/ssh/sshd_config — hardened settings
 
Port 22
Protocol 2
 
# Disable root login
PermitRootLogin no
 
# Disable password authentication (keys only)
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
 
# Allow only specific users
AllowUsers deployuser devuser
 
# Restrict algorithms to modern, secure ones
KexAlgorithms curve25519-sha256,diffie-hellman-group16-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
 
# Timeouts
LoginGraceTime 30
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2

After editing, reload the SSH daemon: sudo systemctl reload sshd. Always keep an existing session open while testing to avoid locking yourself out.

Common Mistakes

  • Using RSA 2048 keys — RSA 2048 is considered borderline by 2026 standards. Use Ed25519 or at minimum RSA 4096 for new keys.
  • No passphrase on private keys — An unencrypted private key file is as dangerous as a plain-text password. Always set a passphrase and use ssh-agent.
  • Reusing one key across all services — Use separate keys for GitHub, production servers, staging, and CI/CD systems. Compromise of one key does not affect others.
  • Enabling ForwardAgent yes to untrusted servers — Agent forwarding allows a compromised server to use your cached keys to connect to other systems. Enable it only for trusted jump hosts.
  • Never rotating keys — Rotate keys annually at minimum, or immediately after any team member with key access leaves the organization.

Best Practices

  • Generate a separate Ed25519 key for each service or environment: GitHub, production, staging, CI/CD.
  • Store key passphrases in a password manager (1Password, Bitwarden) — not in plain text or notes.
  • Audit ~/.ssh/authorized_keys on servers regularly and remove stale or unknown keys.
  • Use ssh-keygen -l -f ~/.ssh/id_ed25519.pub to print the key fingerprint for verification.
  • In CI/CD pipelines, generate ephemeral deploy keys per pipeline or use short-lived signed certificates rather than long-lived static keys.

Key Takeaways

  • Ed25519 is the recommended SSH key type in 2026 — it is faster and more secure than RSA 2048 or RSA 4096.
  • Private keys must have 600 permissions and ~/.ssh must have 700 permissions — SSH refuses keys with broader permissions.
  • SSH agent caches decrypted keys in memory so passphrases only need to be entered once per session.
  • ~/.ssh/config profiles allow ssh production shorthand instead of typing full connection parameters every time.
  • Disable PasswordAuthentication on all production servers — key-only authentication eliminates brute-force attacks entirely.
  • Agent forwarding (ForwardAgent yes) should only be enabled for trusted jump/bastion hosts, never for arbitrary servers.
  • Use separate key pairs per service so a compromised key does not give access to all systems.
  • Rotate SSH keys at least annually and immediately when a team member with access departs.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading