SSH Keys: Generation, Management, and Best Practices
A practical guide to SSH key authentication. Covers RSA vs Ed25519, key generation, ssh-agent, config file setup, and security best practices for developers.
SSH key authentication is more secure and more convenient than password-based logins. Once set up properly, you can connect to remote servers, push to Git repositories, and manage infrastructure without typing a password — while being significantly more resistant to brute-force attacks.
This guide covers SSH key generation, management, and the security practices that keep your keys safe.
How SSH Key Authentication Works
SSH key authentication uses asymmetric cryptography — a pair of mathematically linked keys:
- Private key — stored on your machine, never shared. This is your identity.
- Public key — placed on servers you want to access. This is like a lock that only your private key can open.
The authentication flow:
- You connect to a server:
ssh user@server.com - The server sends a challenge (random data)
- Your SSH client signs the challenge with your private key
- The server verifies the signature using the public key on file
- If it matches, you are authenticated
No password crosses the network. The private key never leaves your machine.
Key Types: Ed25519 vs RSA
Ed25519 (Recommended)
Ed25519 is the modern choice for SSH keys:
ssh-keygen -t ed25519 -C "your_email@example.com"
Advantages:
- Smaller keys: 256-bit key (68 characters in the public key) vs RSA’s 3072+ bits
- Faster: Key generation, signing, and verification are all faster
- More secure: Based on elliptic curve cryptography with no known weaknesses
- Deterministic signatures: Same input always produces the same signature, reducing side-channel attack surface
The generated key pair:
~/.ssh/id_ed25519 (private key - NEVER share this)
~/.ssh/id_ed25519.pub (public key - safe to share)
RSA
RSA is the older standard, still widely supported:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
When to use RSA:
- Legacy systems that do not support Ed25519
- FIPS-compliant environments that require RSA
- Compatibility with older SSH clients or servers
Key size matters: Always use at least 3072 bits (4096 is recommended). RSA keys below 2048 bits are considered weak.
ECDSA
A third option that falls between RSA and Ed25519:
ssh-keygen -t ecdsa -b 521
ECDSA works well but has a known implementation pitfall: if the random number generator is weak during signing, the private key can be recovered. Ed25519 does not have this vulnerability. Unless you have a specific reason, choose Ed25519.
Generating Keys
Step-by-Step Generation
ssh-keygen -t ed25519 -C "alice@company.com"
You will be prompted for:
File location:
Enter file in which to save the key (/home/alice/.ssh/id_ed25519):
Accept the default or specify a custom path. Use custom paths when you need multiple keys (e.g., separate keys for work and personal GitHub accounts).
Passphrase:
Enter passphrase (empty for no passphrase):
Always set a passphrase. A passphrase encrypts the private key on disk — if someone steals the file, they still cannot use it without the passphrase. Use ssh-agent (covered below) so you do not have to type the passphrase every time.
Multiple Keys
For different services or accounts, generate separate keys:
ssh-keygen -t ed25519 -C "personal" -f ~/.ssh/id_ed25519_personal
ssh-keygen -t ed25519 -C "work" -f ~/.ssh/id_ed25519_work
ssh-keygen -t ed25519 -C "servers" -f ~/.ssh/id_ed25519_servers
Installing Public Keys
Manual Installation
Copy your public key to the server:
ssh-copy-id user@server.com
This appends your public key to ~/.ssh/authorized_keys on the server. If ssh-copy-id is not available:
cat ~/.ssh/id_ed25519.pub | ssh user@server.com "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
GitHub, GitLab, Bitbucket
-
Copy your public key:
# macOS pbcopy < ~/.ssh/id_ed25519.pub # Linux xclip -selection clipboard < ~/.ssh/id_ed25519.pub # Or just print it cat ~/.ssh/id_ed25519.pub -
Add it in the service’s SSH key settings (GitHub: Settings > SSH and GPG keys > New SSH key)
-
Test the connection:
ssh -T git@github.com # Hi alice! You've successfully authenticated...
SSH Agent
The SSH agent holds your decrypted private keys in memory, so you type the passphrase once per session instead of once per connection.
Starting the Agent
# Start agent (most systems do this automatically)
eval "$(ssh-agent -s)"
# Add a key
ssh-add ~/.ssh/id_ed25519
# Add with a timeout (key is removed after 8 hours)
ssh-add -t 8h ~/.ssh/id_ed25519
# List loaded keys
ssh-add -l
# Remove all keys
ssh-add -D
macOS Keychain Integration
macOS can store SSH passphrases in the system keychain:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Add this to ~/.ssh/config to make it persistent:
Host *
AddKeysToAgent yes
UseKeychain yes
Agent Forwarding
Agent forwarding lets you use your local SSH keys on a remote server without copying them there:
ssh -A user@jumpbox.com
# From jumpbox, you can now SSH to other servers using your local keys
Security warning: Agent forwarding exposes your keys to the remote machine’s root user. Only forward to servers you trust. Use ProxyJump instead when possible (see SSH config below).
SSH Config File
The SSH config file (~/.ssh/config) eliminates repetitive command-line options:
# Default settings for all hosts
Host *
AddKeysToAgent yes
IdentitiesOnly yes
ServerAliveInterval 60
# Personal GitHub
Host github.com-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
# Work GitHub
Host github.com-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
# Production server
Host prod
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519_servers
Port 2222
# Jump through bastion
Host internal
HostName 10.0.0.5
User admin
ProxyJump bastion
Host bastion
HostName 203.0.113.20
User admin
IdentityFile ~/.ssh/id_ed25519_servers
Now instead of ssh -i ~/.ssh/id_ed25519_servers -p 2222 deploy@203.0.113.10, you just type ssh prod.
Multiple GitHub Accounts
To use different keys for personal and work GitHub repositories:
- Set up the config as shown above
- Clone with the config alias:
git clone git@github.com-personal:alice/project.git # uses personal key git clone git@github.com-work:company/project.git # uses work key
Security Best Practices
Do
- Always set a passphrase on your private keys
- Use Ed25519 unless you need RSA compatibility
- Use ssh-agent to avoid typing passphrases repeatedly
- Set
IdentitiesOnly yesin your config to prevent sending all keys to every server - Rotate keys periodically — generate new keys yearly and remove old public keys from servers
- Use
ProxyJumpinstead of agent forwarding for bastion hosts - Keep your SSH client updated for security patches
Don’t
- Don’t share private keys — ever. Generate a new key pair for each person/machine.
- Don’t use empty passphrases on keys that access production systems
- Don’t store private keys in repositories, cloud storage, or shared drives
- Don’t use RSA keys shorter than 3072 bits
- Don’t use DSA keys — they are deprecated and limited to 1024 bits
- Don’t disable host key verification (
StrictHostKeyChecking no) in production
File Permissions
SSH enforces strict permissions:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 # private key
chmod 644 ~/.ssh/id_ed25519.pub # public key
chmod 600 ~/.ssh/authorized_keys # server-side
chmod 600 ~/.ssh/config # config file
If permissions are too open, SSH will refuse to use the key.
Generating Keys for Testing
During development and testing, you often need to generate SSH key pairs for configuring CI/CD pipelines, testing deployment scripts, or setting up development environments. Our SSH Key Generator creates Ed25519 and RSA key pairs entirely in your browser — no terminal needed. Keys are generated client-side and never sent to any server, making it safe for creating test keys quickly.
For other secrets you need to keep out of your repositories, see our guide to API key security.
Troubleshooting
# Verbose connection debugging
ssh -v user@server.com
# Very verbose (shows key exchange details)
ssh -vv user@server.com
# Check which key is being offered
ssh -v user@server.com 2>&1 | grep "Offering"
# Test a specific key
ssh -i ~/.ssh/id_ed25519_work -T git@github.com
Common issues:
- “Permission denied (publickey)” — wrong key, missing public key on server, or wrong username
- “Permissions are too open” — fix with
chmod 600 ~/.ssh/id_ed25519 - “Too many authentication failures” — add
IdentitiesOnly yesto your config to stop sending every key - Agent not running — start it with
eval "$(ssh-agent -s)"
SSH key authentication is one of those investments that pays for itself immediately. A few minutes of setup gives you faster, more secure access to every server and service you use. Take the time to set up a proper SSH config and ssh-agent, and you will wonder how you ever managed with passwords.
Comments