SSH Key Authentication with a passphrase

Generate a key pair, deploy it to your server, harden your sshd config β€” and type your passphrase only once per session.

πŸ“– ~12 min readβš™ Linux Β· macOS Β· WindowsπŸ”‘ Ed25519 Β· RSA Β· ssh-agent

Table of Contents

  1. Why key-based SSH with a passphrase?
  2. Generating your key pair
  3. Deploying the public key to the server
  4. Hardening the SSH server config
  5. ssh-agent β€” type your passphrase only once
  6. Simplify connections with ~/.ssh/config
  7. Checklist & best practices

01 Why key-based SSH with a passphrase?

Password authentication is the most common target for brute-force attacks. Public key authentication replaces the password with a cryptographic pair: a private key that stays on your machine and a public key that lives on every server you want to access. Only someone holding the private key can authenticate.

Adding a passphrase to the private key encrypts it on disk. Even if someone steals your key file, it’s useless without the passphrase. You get two independent layers of security without sacrificing convenience β€” that’s where ssh-agent comes in.

πŸ’‘

Algorithm recommendation: Use Ed25519 β€” it’s faster, produces shorter keys, and offers equivalent or better security compared to RSA-4096. Only fall back to RSA if you need to connect to very old systems.

02 Generating your key pair

Generate an Ed25519 key (recommended)

Run this on your local machine β€” never on the server.

# -C adds a comment (usually your email) to identify the key
ssh-keygen -t ed25519 -C "you@example.com"

Fallback: RSA 4096-bit

Only use this if your target server is too old to support Ed25519.

ssh-keygen -t rsa -b 4096 -C "you@example.com"

What ssh-keygen will ask you

  1. File path β€” press Enter to accept the default (~/.ssh/id_ed25519). Use a custom name if you manage multiple keys.
  2. Passphrase β€” choose a long, memorable phrase (e.g. MyDogIsCalledMax42!). You’ll confirm it twice.

πŸ”’

Your private key (~/.ssh/id_ed25519) must never leave your machine. Only the public key (~/.ssh/id_ed25519.pub) is copied to servers.

Verify the generated files

ls -la ~/.ssh/
# You should see:
# -rw-------  id_ed25519        ← private key (permissions 600)
# -rw-r--r--  id_ed25519.pub   ← public key (safe to share)

03 Deploying the public key to the server

Recommended: ssh-copy-id

This command appends your public key to ~/.ssh/authorized_keys on the remote server and sets the correct permissions automatically.

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server

If your server runs SSH on a non-standard port:

ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 user@your-server

Manual method (Windows / no ssh-copy-id)

# 1. Print the public key on your local machine
cat ~/.ssh/id_ed25519.pub

# 2. On the server, paste and save it
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "PASTE_YOUR_PUBLIC_KEY_HERE" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Test the key-based login

Before touching the server config, confirm authentication by key actually works:

ssh -i ~/.ssh/id_ed25519 user@your-server
# You should be prompted for your passphrase, then logged in.

⚠️

Keep an open session while reconfiguring the server. If you make a mistake and lock yourself out, an active session is your lifeline.

04 Hardening the SSH server config

Edit sshd_config on the server

sudo nano /etc/ssh/sshd_config

Key directives to set

# Enable public-key authentication
PubkeyAuthentication     yes
AuthorizedKeysFile       .ssh/authorized_keys

# Disable password authentication
PasswordAuthentication   no

# Disable direct root login
PermitRootLogin          no

# Deny empty passwords
PermitEmptyPasswords     no

# (Optional) Restrict to specific users
AllowUsers               youruser

Validate and restart

Always test the config file before restarting the daemon β€” a syntax error can make the service fail to start.

# Dry-run: check for syntax errors
sudo sshd -t

# If no output (no errors), restart
sudo systemctl restart sshd

🚫

Set PasswordAuthentication no only after verifying that key-based login works. Disabling passwords before that locks you out permanently.

05 ssh-agent β€” type your passphrase only once

ssh-agent is a background process that holds your decrypted private key in memory. Once you unlock your key once, the agent handles all subsequent authentications transparently β€” no passphrase prompt on every ssh call.

Linux β€” start the agent and add your key

# Start the agent
eval "$(ssh-agent -s)"

# Add the key (passphrase asked once here)
ssh-add ~/.ssh/id_ed25519

# Confirm the key is loaded
ssh-add -l

Auto-start on every terminal session

Add this block to your ~/.bashrc or ~/.zshrc:

# Start ssh-agent only if not already running
if [ -z "$SSH_AUTH_SOCK" ]; then
  eval "$(ssh-agent -s)"
  ssh-add ~/.ssh/id_ed25519 2>/dev/null
fi

πŸ’‘

Use ssh-add -t 28800 to set an 8-hour time-to-live on the loaded key. After that, the passphrase is required again β€” a good balance between security and convenience.

macOS β€” integrate with the system Keychain

macOS ships with a Keychain-aware ssh-agent. Add this to ~/.ssh/config:

Host *
    AddKeysToAgent  yes
    UseKeychain     yes
    IdentityFile    ~/.ssh/id_ed25519

Then add the key to the Keychain once:

ssh-add --apple-use-keychain ~/.ssh/id_ed25519

After this, the passphrase is remembered permanently across reboots β€” you’ll never be asked again.

Windows β€” OpenSSH (PowerShell)

# Run as Administrator
Set-Service ssh-agent -StartupType Automatic
Start-Service ssh-agent

# Add the key
ssh-add $env:USERPROFILE\.ssh\id_ed25519

Windows β€” PuTTY / Pageant

Launch Pageant, click Add Key, select your .ppk key file, and enter the passphrase. It stays unlocked for the whole Windows session.

Removing keys from the agent

# Remove a specific key
ssh-add -d ~/.ssh/id_ed25519

# Remove all keys
ssh-add -D

06 Simplify connections with ~/.ssh/config

The client config file lets you define aliases and per-host options so you can type ssh prod instead of a long command every time.

# ~/.ssh/config

Host staging
    HostName      192.168.1.100
    User          alice
    Port          22
    IdentityFile  ~/.ssh/id_ed25519
    AddKeysToAgent yes

Host prod
    HostName      prod.example.com
    User          deploy
    Port          2222
    IdentityFile  ~/.ssh/id_ed25519_prod
    AddKeysToAgent yes

Now connect with:

ssh staging
# Equivalent to: ssh -i ~/.ssh/id_ed25519 -p 22 alice@192.168.1.100

πŸ’‘

Set permissions correctly on your config file: chmod 600 ~/.ssh/config. SSH will refuse to read the file if it’s world-readable.

07 Checklist & best practices

StepAction
01Generate an Ed25519 key pair with ssh-keygen and set a strong passphrase
02Copy the public key to the server with ssh-copy-id
03Verify key-based login works before changing anything on the server
04Edit /etc/ssh/sshd_config β€” disable password auth, block root login
05Run sudo sshd -t to validate, then systemctl restart sshd
06Set up ssh-agent (or Keychain on macOS) to unlock once per session
07Create ~/.ssh/config with per-host aliases and AddKeysToAgent yes

Security best practices

  • Use a unique, long passphrase for each private key.
  • One key per context β€” separate keys for personal use, work, CI/CD pipelines.
  • Back up your private key in a secure password manager (Bitwarden, 1Password, etc.).
  • Set a TTL on ssh-agent with -t so keys are flushed automatically.
  • Revoke compromised keys immediately by removing the relevant line from ~/.ssh/authorized_keys on every server.
  • Enable SSH logging on the server to detect intrusion attempts: LogLevel VERBOSE in sshd_config.

🚨

If you forget your passphrase, the private key is gone forever. Generate a new pair and redeploy the public key to all your servers.