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