TL;DR: Generate separate SSH keys for different services (GitHub personal, GitHub work, VPS). Configure ~/.ssh/config with host aliases. Clone and push using the alias, not the original hostname. You get clean separation without managing credentials in code.

The Problem: One Key Isn’t Enough

Early in your career, one SSH key worked: you generated id_rsa, added it to GitHub, and every Git operation used the same key.

As you grow, you have multiple contexts:

  • Personal GitHub projects
  • Work GitHub organization (different account)
  • VPS deployment servers
  • Private repositories with restricted access

Using one key for everything means anyone with that key can access everything. It violates the principle of least privilege. Better approach: separate keys for separate purposes, configured centrally in SSH config.

This guide covers the real workflow: generating keys, testing connections, and configuring Git to use the right key automatically.

Step 1: Generate SSH Keys for Each Context

SSH keys should be named by their purpose, not by their host. Use clear naming:

# For personal GitHub projects
ssh-keygen -t ed25519 -C "personal-github" -f ~/.ssh/id_ed25519_github_personal

# For work GitHub organization
ssh-keygen -t ed25519 -C "work-github" -f ~/.ssh/id_ed25519_github_work

# For VPS/deployment server
ssh-keygen -t ed25519 -C "vps-deployment" -f ~/.ssh/id_ed25519_vps

When prompted for a passphrase, use one (it protects the key if your machine is compromised). You’ll enter it once per session due to ssh-agent.

Why ed25519? It’s modern, secure, and produces smaller keys (71 bytes vs 1700+ for RSA). If you need broader compatibility, use rsa -b 4096, but ed25519 is preferred for new setups.

Each command creates two files:

  • Private key: ~/.ssh/id_ed25519_github_personal (keep secret)
  • Public key: ~/.ssh/id_ed25519_github_personal.pub (share with services)

Step 2: Add Public Keys to Services

Display the public key content and add it where needed:

cat ~/.ssh/id_ed25519_github_personal.pub

Copy the output and add it to GitHub (Settings → SSH Keys → New SSH Key).

Repeat for work GitHub, VPS admin panel, or wherever you need SSH access.

Important: Each service gets one public key. You don’t share private keys.

Step 3: Configure SSH Config for Automatic Key Selection

Create or edit ~/.ssh/config:

nano ~/.ssh/config

Add entries for each context. Here’s an anonymized example:

# Personal GitHub
Host github.com-personal
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_github_personal
  IdentitiesOnly yes

# Work GitHub
Host github.com-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_github_work
  IdentitiesOnly yes

# VPS (anonymized)
Host vps-deploy
  HostName 203.0.113.42
  User deploy
  IdentityFile ~/.ssh/id_ed25519_vps
  IdentitiesOnly yes

# Another VPS or staging server
Host staging-server
  HostName 198.51.100.89
  User ubuntu
  IdentityFile ~/.ssh/id_ed25519_vps
  IdentitiesOnly yes

Key fields:

  • Host: Alias you’ll use in commands (not the real hostname)
  • HostName: Actual IP or domain name
  • User: SSH username on that host
  • IdentityFile: Path to private key for this host
  • IdentitiesOnly yes: Only try the specified key (prevents SSH from trying all keys, which can cause account lockouts)

Save the file (Ctrl+O, Enter, Ctrl+X).

Set correct permissions:

chmod 600 ~/.ssh/config
chmod 600 ~/.ssh/id_ed25519_*
chmod 644 ~/.ssh/id_ed25519_*.pub

SSH is strict about permissions. Wrong modes cause “bad permissions” errors.

Step 4: Test Connections

Test SSH connection to each host:

# Test GitHub personal
ssh -T github.com-personal

# Expected output: Hi username! You've successfully authenticated...
# Test VPS
ssh vps-deploy

# Should log in or show connection successful (depends on server)
# Test with verbose output if something fails
ssh -v vps-deploy

The -v flag shows which key SSH tried and why it succeeded or failed. Useful for debugging.

Step 5: Clone Repositories Using SSH Aliases

This is where the setup pays off. Clone using the alias, not the original hostname:

# Wrong (uses default GitHub identity):
git clone git@github.com:username/personal-repo.git

# Right (uses the specific key via alias):
git clone git@github.com-personal:username/personal-repo.git

The key difference: github.com-personal instead of github.com. SSH reads ~/.ssh/config, finds the matching host alias, and uses the specified key.

For VPS:

# SSH into the server
ssh vps-deploy

# Or copy files
scp -r ./dist vps-deploy:/home/deploy/app/

Step 6: Configure Git for Multiple Accounts (Optional)

If you have multiple GitHub accounts and want different author names in commits, configure Git per directory:

# Global config (default)
git config --global user.name "Your Name"
git config --global user.email "personal@example.com"

# Work project (local config, only for this repo)
cd ~/projects/work-repo
git config user.name "Your Name (Work)"
git config user.email "work@company.com"

Verify the local config:

git config user.email  # Shows local value if set, otherwise global

Step 7: Use SSH Agent to Cache Passphrases

If your keys have passphrases (they should), typing the passphrase every push is tedious.

SSH agent caches decrypted keys in memory for the session. Add to your shell config (~/.bashrc, ~/.zshrc):

# Start SSH agent if not running
if [ -z "$SSH_AUTH_SOCK" ]; then
  eval "$(ssh-agent -s)"
  # Add all keys to agent
  ssh-add ~/.ssh/id_ed25519_*
fi

On first login, enter each passphrase once. For the rest of the session, SSH uses the cached key.

On macOS, the system Keychain stores SSH passphrases by default; you usually don’t need manual setup.

Troubleshooting

“Permission denied (publickey)”:

  • Verify public key is added to the service (GitHub, VPS, etc.)
  • Test with -v to see which key SSH tried
  • Check IdentitiesOnly yes is set in SSH config

“Bad permissions” for ~/.ssh/config or private key:

  • Run the chmod commands above
  • SSH requires strict ownership (must be owned by your user, not root)

SSH tries wrong key first:

  • Ensure IdentitiesOnly yes is in SSH config
  • Without it, SSH tries keys in order until one works, risking account lockouts

Can’t connect to GitHub but VPS works:

  • SSH to GitHub uses git user, not your username
  • Verify User git is in the GitHub host alias

Common Workflow Example

Here’s a practical daily workflow:

# Clone personal project (uses id_ed25519_github_personal)
git clone git@github.com-personal:myusername/blog.git
cd blog
git config user.name "My Name"
git config user.email "personal@example.com"

# Make changes, commit, push
echo "New post" >> content.md
git add content.md
git commit -m "Add new post"
git push origin main

# Later: SSH into production to deploy
ssh vps-deploy
cd /app/blog
git pull origin main
npm run build

The entire flow uses SSH keys managed through config aliases. No manual credential switching, no tokens or passwords in environment variables.

SSH Key Rotation and Cleanup

Over time, you may need to rotate keys (regenerate them). When you do:

  1. Generate new key with same purpose name
  2. Update ~/.ssh/config to point to new key
  3. Add new public key to services
  4. Remove old public key from services
  5. Delete old private key: rm ~/.ssh/id_ed25519_old

This keeps your setup current without disrupting workflow.

Conclusion

Multiple SSH keys aren’t complicated. They’re a standard practice that improves security and convenience.

The workflow is:

  1. Generate keys per purpose
  2. Add public keys to services
  3. Configure SSH aliases in ~/.ssh/config
  4. Use aliases in Git clone and SSH commands
  5. Let SSH agent cache passphrases

Once set up, you forget about it. Git just works, using the right key automatically. You’ve gained separation of concerns, better security, and a cleaner mental model of your credentials.