Introduction
SSH key-based authentication is more secure and more convenient than password authentication. Once set up, you can log into remote servers without typing a password โ while actually being more secure, since keys are cryptographically stronger than passwords and can’t be brute-forced.
How It Works
Host A (your machine) Host B (remote server)
โโโ ~/.ssh/id_rsa โโโ ~/.ssh/authorized_keys
โ (private key) โ (contains your public key)
โโโ ~/.ssh/id_rsa.pub โโโ (matches against incoming key)
(public key)
When you connect, SSH proves you have the private key without ever sending it. The server checks if your public key is in authorized_keys and grants access if it matches.
Step 1: Generate a Key Pair
Run this on your local machine (Host A):
cd ~/.ssh
ssh-keygen -t ed25519 -C "[email protected]"
Options:
-t ed25519โ use Ed25519 (modern, fast, secure). Usersa -b 4096for older systems.-C "comment"โ adds a comment to identify the key (usually your email)
You’ll be prompted for a passphrase โ use one. It encrypts the private key on disk, so even if someone steals your key file, they can’t use it without the passphrase.
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519): [Enter]
Enter passphrase (empty for no passphrase): [type a passphrase]
Enter same passphrase again: [repeat]
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub
# View your keys
ls ~/.ssh/
# id_ed25519 (private key โ never share this)
# id_ed25519.pub (public key โ safe to share)
# View the public key
cat ~/.ssh/id_ed25519.pub
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... [email protected]
Step 2: Copy the Public Key to the Remote Host
Method 1: ssh-copy-id (Easiest)
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host_B
This appends your public key to ~/.ssh/authorized_keys on Host B automatically.
Method 2: Manual Copy
If ssh-copy-id isn’t available:
# Copy the public key content
cat ~/.ssh/id_ed25519.pub
# On Host B, append it to authorized_keys
mkdir -p ~/.ssh
echo "ssh-ed25519 AAAA... [email protected]" >> ~/.ssh/authorized_keys
Method 3: Pipe via SSH
cat ~/.ssh/id_ed25519.pub | ssh user@host_B "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
Step 3: Set Correct Permissions on Host B
SSH is strict about file permissions โ it will refuse to use keys if permissions are too open:
# On Host B
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
If you’re setting up for root:
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys
chown root:root /root/.ssh /root/.ssh/authorized_keys
Step 4: Add Key to SSH Agent (Optional but Recommended)
The SSH agent holds your decrypted private key in memory so you only need to enter the passphrase once per session:
# Start the agent (usually auto-started)
eval "$(ssh-agent -s)"
# Add your key
ssh-add ~/.ssh/id_ed25519
# List loaded keys
ssh-add -l
# Remove all keys from agent
ssh-add -D
On macOS, add to ~/.ssh/config to auto-load keys:
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
Step 5: Test the Connection
ssh user@host_B
# Should connect without asking for a password
If it still asks for a password, debug with verbose mode:
ssh -v user@host_B
Managing Multiple Keys
SSH Config File
Use ~/.ssh/config to manage multiple keys and hosts:
# Default key for all hosts
Host *
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
# Work servers โ use work key
Host *.work.example.com
User alice
IdentityFile ~/.ssh/id_work
# Personal GitHub
Host github.com
User git
IdentityFile ~/.ssh/id_github
# Personal server with non-standard port
Host myserver
HostName 203.0.113.42
User ubuntu
Port 2222
IdentityFile ~/.ssh/id_personal
# Jump host (bastion)
Host internal-server
HostName 10.0.0.5
User ubuntu
ProxyJump bastion.example.com
With this config:
ssh myserver # uses the config above
ssh internal-server # automatically jumps through bastion
Multiple GitHub Accounts
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_personal
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_work
# Clone personal repo
git clone git@github-personal:username/repo.git
# Clone work repo
git clone git@github-work:company/repo.git
Copying Keys to Multiple Servers
#!/bin/bash
# Deploy your public key to multiple servers
SERVERS=(
"[email protected]"
"[email protected]"
"[email protected]"
)
for server in "${SERVERS[@]}"; do
echo "Copying key to $server..."
ssh-copy-id -i ~/.ssh/id_ed25519.pub "$server"
done
Disabling Password Authentication (Security Hardening)
Once key-based auth is working, disable password login on the server:
# On Host B โ edit /etc/ssh/sshd_config
sudo vim /etc/ssh/sshd_config
# Disable password authentication
PasswordAuthentication no
ChallengeResponseAuthentication no
# Only allow key-based auth
PubkeyAuthentication yes
# Disable root login (use sudo instead)
PermitRootLogin no
# Limit to specific users
AllowUsers alice bob
# Restart SSH daemon
sudo systemctl restart sshd
# Test in a NEW terminal before closing your current session!
ssh user@host_B
Warning: Always test in a new terminal before closing your existing session. If you lock yourself out, you’ll need console access to fix it.
Troubleshooting
Permission denied (publickey)
# Debug with verbose output
ssh -vvv user@host_B 2>&1 | grep -E "Offering|Authentications|Permission"
# Common causes:
# 1. Wrong permissions on ~/.ssh or authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
# 2. Wrong key being offered
ssh -i ~/.ssh/id_ed25519 user@host_B
# 3. authorized_keys has wrong format (must be one key per line)
cat ~/.ssh/authorized_keys
# 4. SELinux blocking (RHEL/CentOS)
restorecon -Rv ~/.ssh
Check SSH Server Logs
# On the server
sudo journalctl -u sshd -f
sudo tail -f /var/log/auth.log # Debian/Ubuntu
sudo tail -f /var/log/secure # RHEL/CentOS
Key Types Comparison
| Type | Key Size | Security | Speed | Compatibility |
|---|---|---|---|---|
| Ed25519 | 256-bit | Excellent | Fastest | OpenSSH 6.5+ |
| ECDSA | 256-521 bit | Good | Fast | Widely supported |
| RSA | 2048-4096 bit | Good (4096) | Slower | Universal |
| DSA | 1024 bit | Weak | โ | Deprecated |
Recommendation: Use Ed25519 for new keys. Use RSA 4096 only if you need compatibility with very old systems.
Comments