Set Up SSH Key Authentication for Passwordless and Secure Server Access
Every time you type a password to log into a remote server, you’re doing it the slow and less secure way. SSH key authentication replaces passwords with a cryptographic key pair — a private key that stays on your machine and a public key that lives on the server. The result: faster logins, stronger security, and no more passwords to remember or type.
This guide covers everything from generating your first key pair to hardening your server by disabling password authentication entirely.
How SSH Key Authentication Works
SSH key authentication uses asymmetric cryptography. Here’s the simplified flow:
- You generate a key pair: a private key (kept secret on your machine) and a public key (shared with servers).
- You place the public key on the remote server in
~/.ssh/authorized_keys. - When you connect, the server sends a challenge encrypted with your public key.
- Your SSH client uses the private key to decrypt the challenge and respond.
- The server verifies the response — if it matches, you’re in.
Your private key never leaves your machine and is never transmitted over the network.
Choosing a Key Type
OpenSSH supports several key algorithms:
| Algorithm | Key Size | Speed | Security | Recommendation |
|---|---|---|---|---|
ed25519 | 256 bits | Very fast | Excellent | Best choice for most users |
rsa | 2048–4096 bits | Slower | Good (at 4096) | Use if ed25519 isn’t supported |
ecdsa | 256/384/521 bits | Fast | Good | Avoid (potential implementation concerns) |
dsa | 1024 bits | Slow | Weak | Deprecated — do not use |
Ed25519 is the recommended algorithm. It produces short keys, is fast to sign and verify, and has no known weaknesses. It’s supported by OpenSSH 6.5+ (released January 2014), so virtually all modern systems support it.
Step 1: Generate an SSH Key Pair
On Linux or macOS
Open a terminal and run:
ssh-keygen -t ed25519 -C "your_email@example.com"
You’ll see:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/youruser/.ssh/id_ed25519):
Press Enter to accept the default location. Then you’ll be asked for a passphrase:
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Set a passphrase. This encrypts your private key on disk, so even if someone steals the key file, they can’t use it without the passphrase. You can use ssh-agent to avoid retyping it (covered below).
This creates two files:
~/.ssh/id_ed25519— your private key (never share this)~/.ssh/id_ed25519.pub— your public key (safe to share)
On Windows (OpenSSH)
Windows 10/11 includes OpenSSH. Open PowerShell and run:
ssh-keygen -t ed25519 -C "your_email@example.com"
Keys are saved to C:\Users\YourUser\.ssh\id_ed25519 and id_ed25519.pub.
On Windows (PuTTYgen)
If you use PuTTY:
- Open PuTTYgen (included with PuTTY installer from putty.org)
- Select EdDSA (Ed25519)
- Click Generate and move your mouse to generate randomness
- Set a passphrase
- Click Save private key (
.ppkfile for PuTTY) - Copy the public key from the text box at the top
Fallback: RSA 4096
If your server is very old and doesn’t support Ed25519:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
Step 2: Copy the Public Key to the Server
Using ssh-copy-id (Linux/macOS)
The easiest method:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server-ip
This:
- Connects to the server using your password (one last time)
- Creates
~/.ssh/authorized_keyson the server if it doesn’t exist - Appends your public key to the file
- Sets correct permissions automatically
Manual Method
If ssh-copy-id isn’t available (e.g., on Windows or some macOS installs):
# Display your public key
cat ~/.ssh/id_ed25519.pub
Copy the output (it’s one long line starting with ssh-ed25519 AAAA...).
Then SSH into your server with your password:
ssh user@server-ip
On the server, add the key:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "ssh-ed25519 AAAA...your-full-public-key..." >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
From Windows PowerShell
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh user@server-ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
Step 3: Test the Connection
ssh user@server-ip
If everything is set up correctly, you’ll be logged in without being asked for a password (you may be asked for your key’s passphrase if you set one).
Step 4: Set Up SSH Agent
The SSH agent holds your decrypted private keys in memory so you only type your passphrase once per session.
Linux
# Start the agent
eval "$(ssh-agent -s)"
# Add your key
ssh-add ~/.ssh/id_ed25519
To start the agent automatically, add eval "$(ssh-agent -s)" to your ~/.bashrc or ~/.zshrc.
macOS
macOS has built-in SSH agent integration with Keychain:
# Add key to agent and store passphrase in Keychain
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Add this to ~/.ssh/config so it persists across reboots:
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
Windows (OpenSSH Agent)
# Start the agent service
Get-Service ssh-agent | Set-Service -StartupType Automatic -PassThru | Start-Service
# Add your key
ssh-add $env:USERPROFILE\.ssh\id_ed25519
Step 5: Configure SSH for Convenience
Create or edit ~/.ssh/config to set up shortcuts for your servers:
Host myserver
HostName 203.0.113.50
User deploy
IdentityFile ~/.ssh/id_ed25519
Port 22
Host production
HostName prod.example.com
User admin
IdentityFile ~/.ssh/id_ed25519
Port 2222
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
Now instead of typing ssh deploy@203.0.113.50, you just type:
ssh myserver
This config also works with scp, rsync, and git over SSH.
Step 6: Disable Password Authentication (Server Hardening)
Once SSH keys are working, disable password login on the server to prevent brute-force attacks.
Important: Make sure your key-based login works before doing this, or you’ll lock yourself out.
On the server, edit the SSH daemon config:
sudo nano /etc/ssh/sshd_config
Find and set these directives:
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
PubkeyAuthentication yes
Restart the SSH service:
# Debian/Ubuntu
sudo systemctl restart ssh
# CentOS/RHEL/Fedora
sudo systemctl restart sshd
Test by opening a new terminal and connecting. If it works with your key, you’re set. Password-based login is now disabled.
Step 7: Add Keys to GitHub, GitLab, and Bitbucket
SSH keys also work for Git operations over SSH.
GitHub
- Copy your public key:
cat ~/.ssh/id_ed25519.pub - Go to github.com/settings/keys
- Click New SSH key
- Paste your public key and save
Test the connection:
ssh -T git@github.com
# Output: Hi username! You've successfully authenticated...
GitLab
- Go to gitlab.com/-/user_settings/ssh_keys
- Paste your public key and save
Bitbucket
- Go to Personal Settings > SSH keys at bitbucket.org/account/settings/ssh-keys/
- Click Add key and paste your public key
Managing Multiple Keys
If you need different keys for different servers or services, generate additional keys:
ssh-keygen -t ed25519 -C "work" -f ~/.ssh/id_ed25519_work
ssh-keygen -t ed25519 -C "personal" -f ~/.ssh/id_ed25519_personal
Then configure ~/.ssh/config:
Host github.com
IdentityFile ~/.ssh/id_ed25519_personal
Host gitlab.company.com
IdentityFile ~/.ssh/id_ed25519_work
Host *.internal.company.com
IdentityFile ~/.ssh/id_ed25519_work
User deployer
Troubleshooting
”Permission denied (publickey)”
This is the most common error. Check these in order:
# 1. Verify your key is loaded in the agent
ssh-add -l
# 2. Test with verbose output to see what's happening
ssh -vvv user@server-ip
# 3. On the server, check permissions
ls -la ~/.ssh/
ls -la ~/.ssh/authorized_keys
# 4. Check the server's auth log
sudo tail -20 /var/log/auth.log # Debian/Ubuntu
sudo tail -20 /var/log/secure # CentOS/RHEL
“Agent has no identities”
Your key isn’t loaded in the agent:
ssh-add ~/.ssh/id_ed25519
Key permissions are too open
SSH refuses to use a private key with loose permissions:
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 700 ~/.ssh
Server still asking for password
- Verify the public key is in
~/.ssh/authorized_keyson the server - Check that
PubkeyAuthentication yesis set in/etc/ssh/sshd_config - Ensure the home directory,
.sshdirectory, andauthorized_keysfile aren’t writable by others - Check if SELinux is blocking access:
restorecon -R ~/.ssh
Security Best Practices
- Always use a passphrase on your private key — it’s your last line of defense if the key file is stolen
- Use Ed25519 over RSA when possible — smaller keys, faster operations, better security
- One key per device — don’t copy private keys between machines; generate a new pair for each device
- Disable password auth on servers once key auth is confirmed working
- Rotate keys periodically — generate new keys annually and remove old public keys from servers
- Set
PermitRootLogin prohibit-passwordinsshd_config(ornofor maximum security) - Use
ssh-agentinstead of passphrase-less keys — you get convenience without sacrificing security - Audit
authorized_keysregularly — remove keys for people or devices that no longer need access
Quick Reference
| Task | Command |
|---|---|
| Generate Ed25519 key | ssh-keygen -t ed25519 -C "email" |
| Copy key to server | ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host |
| Start SSH agent | eval "$(ssh-agent -s)" |
| Add key to agent | ssh-add ~/.ssh/id_ed25519 |
| List loaded keys | ssh-add -l |
| Test GitHub connection | ssh -T git@github.com |
| Debug connection | ssh -vvv user@host |
| View public key | cat ~/.ssh/id_ed25519.pub |
Conclusion
SSH key authentication is one of the most impactful security improvements you can make for your server workflow. It eliminates the risks of password-based logins — brute-force attacks, password reuse, credential leaks — and replaces them with strong cryptographic proof of identity. Combined with ssh-agent and an SSH config file, you get both better security and a faster workflow. Once you’ve switched to SSH keys, you won’t go back.