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:

  1. You connect to a server: ssh user@server.com
  2. The server sends a challenge (random data)
  3. Your SSH client signs the challenge with your private key
  4. The server verifies the signature using the public key on file
  5. If it matches, you are authenticated

No password crosses the network. The private key never leaves your machine.

Key Types: Ed25519 vs RSA

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

  1. 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
  2. Add it in the service’s SSH key settings (GitHub: Settings > SSH and GPG keys > New SSH key)

  3. 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:

  1. Set up the config as shown above
  2. 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 yes in 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 ProxyJump instead 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 yes to 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.