SSH keys are the gold standard for secure server authentication, replacing passwords with cryptographic key pairs. Whether you are setting up a new development machine, configuring CI/CD pipelines, or hardening production servers, understanding how to generate and manage SSH keys is a fundamental skill. This comprehensive guide covers everything from key algorithm selection (Ed25519 vs RSA vs ECDSA) to advanced SSH configuration, agent management, and troubleshooting common issues.
What Are SSH Keys?
SSH (Secure Shell) keys are cryptographic key pairs used for authentication. Instead of typing a password every time you connect to a remote server, SSH keys let you prove your identity using public-key cryptography. This is both more secure and more convenient than password-based authentication.
An SSH key pair consists of two files:
- Private key: Private key: Stays on your local machine. Never share this file with anyone. It is analogous to a physical key that unlocks a door.
- Public key: Public key: Placed on every server you want to access. It is analogous to a lock — anyone can see it, but only the matching private key can open it.
How SSH Key Authentication Works
# SSH Key Authentication Flow
Client Server
│ │
│── 1. Connection request ─────>│
│ │
│<── 2. Random challenge ───────│ (encrypted with your public key)
│ │
│── 3. Decrypted response ─────>│ (signed with your private key)
│ │
│<── 4. Access granted ─────────│ (response verified)
│ │This means even if an attacker intercepts the network traffic, they cannot authenticate as you without possessing your private key. Passwords, on the other hand, can be captured by keyloggers, phishing, or brute-force attacks.
Ed25519 vs RSA vs ECDSA: Algorithm Comparison
There are several algorithms available for SSH key generation. The three most common are RSA, ECDSA, and Ed25519. Each has different security properties, performance characteristics, and compatibility considerations.
| Feature | Ed25519 | RSA | ECDSA |
|---|---|---|---|
| Introduced | 2014 (OpenSSH 6.5) | 1995 (SSH-1) | 2011 (OpenSSH 5.7) |
| Security Level | ~128-bit (equivalent to RSA-3072) | 112-bit (2048) / 128-bit (3072) / 192-bit (4096) | 128-bit (P-256) / 192-bit (P-384) |
| Private Key Size | 64 bytes (fixed) | ~3,200 bytes (4096-bit) | ~256 bytes (P-256) |
| Public Key Size | 32 bytes (fixed) | ~512 bytes (4096-bit) | ~64 bytes (P-256) |
| Sign Speed | Very fast | Slow | Fast |
| Verify Speed | Very fast | Fast | Moderate |
| Compatibility | OpenSSH 6.5+ (2014), most modern systems | Universal (all SSH implementations) | OpenSSH 5.7+, but NIST curve concerns |
| Recommendation | Best choice for new keys | Use 4096-bit if Ed25519 not supported | Generally avoid — prefer Ed25519 |
Ed25519 is the recommended algorithm for new SSH keys. It provides excellent security with small key sizes, fast operations, and resistance to several classes of implementation attacks. RSA-4096 remains a solid fallback for systems that do not support Ed25519. ECDSA is generally not recommended due to concerns about the NIST P-256 curve and sensitivity to poor random number generation.
Generate an Ed25519 SSH Key
Ed25519 keys are the modern standard. They are fast, secure, and produce compact key files. Here is how to generate one step by step:
Step 1: Open your terminal (Linux/macOS) or Git Bash / PowerShell (Windows).
Step 2: Run the ssh-keygen command with the Ed25519 algorithm:
ssh-keygen -t ed25519 -C "your_email@example.com"Step 3: When prompted for a file location, press Enter to accept the default (~/.ssh/id_ed25519), or specify a custom path:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519):
# Press Enter for default, or type a custom path like:
# /home/user/.ssh/id_ed25519_githubStep 4: Enter a strong passphrase when prompted (recommended), or press Enter for no passphrase:
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
# Use a strong passphrase like: correct-horse-battery-stapleStep 5: Verify the key was created:
ls -la ~/.ssh/id_ed25519*
# Expected output:
-rw------- 1 user user 464 Jan 15 10:30 /home/user/.ssh/id_ed25519
-rw-r--r-- 1 user user 105 Jan 15 10:30 /home/user/.ssh/id_ed25519.pub
# View your public key:
cat ~/.ssh/id_ed25519.pub
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... your_email@example.comThe command generates two files: id_ed25519 (private key) and id_ed25519.pub (public key). The -C flag adds a comment (typically your email) to help identify the key.
Useful ssh-keygen flags for Ed25519:
-t ed25519: -t ed25519: Specifies the Ed25519 algorithm.-C "comment": -C "comment": Adds an identifying comment (usually your email).-f /path/to/key: -f /path/to/key: Specifies the output file path.-N "passphrase": -N "passphrase": Sets the passphrase non-interactively (useful in scripts).-a 100: -a 100: Number of KDF rounds for passphrase protection (higher = slower brute force). Default is 16.
# Generate Ed25519 key with all options in one command:
ssh-keygen -t ed25519 -C "work@company.com" -f ~/.ssh/id_ed25519_work -a 100
# Generate key non-interactively (for scripts):
ssh-keygen -t ed25519 -C "deploy@ci" -f ~/.ssh/id_deploy -N "" -a 16Generate an RSA SSH Key (4096-bit)
If you need compatibility with older systems that do not support Ed25519, use RSA with a minimum key size of 4096 bits. RSA-2048 is still considered secure but offers a smaller security margin for the future.
Step 1: Run the ssh-keygen command with RSA and 4096 bits:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"Step 2: Follow the same prompts as above (file location and passphrase).
Step 3: Verify the key:
ls -la ~/.ssh/id_rsa*
# Expected output:
-rw------- 1 user user 3,381 Jan 15 10:35 /home/user/.ssh/id_rsa
-rw-r--r-- 1 user user 749 Jan 15 10:35 /home/user/.ssh/id_rsa.pub
# View the public key:
cat ~/.ssh/id_rsa.pub
# ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQ... your_email@example.com
# Verify key details:
ssh-keygen -l -f ~/.ssh/id_rsa.pub
# 4096 SHA256:abc123... your_email@example.com (RSA)Important: Important: Never use RSA keys shorter than 2048 bits. RSA-1024 has been considered insecure since 2013. For maximum security margin, always use 4096 bits.
Useful ssh-keygen flags for RSA:
-b 4096: -b 4096: Specifies 4096-bit key length (default is 3072 in modern OpenSSH).-o: -o: Uses the new OpenSSH private key format (more resistant to brute-force). This is the default since OpenSSH 7.8.
SSH Key File Locations
SSH keys and configuration files are stored in the ~/.ssh/ directory. Understanding this directory structure is essential for managing your SSH setup.
~/.ssh/
├── id_ed25519 # Ed25519 private key (chmod 600)
├── id_ed25519.pub # Ed25519 public key (chmod 644)
├── id_rsa # RSA private key (chmod 600)
├── id_rsa.pub # RSA public key (chmod 644)
├── config # SSH client config (chmod 600)
├── known_hosts # Server fingerprints (chmod 644)
└── authorized_keys # Allowed public keys (chmod 600, server-side)| File | Purpose | Permissions |
|---|---|---|
| ~/.ssh/ directory | The parent directory must also have correct permissions | 700 (drwx------) |
| id_ed25519 | Ed25519 private key | 600 (-rw-------) |
| id_ed25519.pub | Ed25519 public key | 644 (-rw-r--r--) |
| id_rsa | RSA private key | 600 (-rw-------) |
| id_rsa.pub | RSA public key | 644 (-rw-r--r--) |
| config | SSH client configuration file | 600 (-rw-------) |
| known_hosts | List of server fingerprints you have connected to (prevents MITM attacks) | 644 (-rw-r--r--) |
| authorized_keys | Public keys allowed to log in to this server (on the server side) | 600 (-rw-------) |
On Windows, the SSH directory is typically located at C:\Users\YourUsername\.ssh\. If you are using Git Bash, it maps to ~/.ssh/ as on Linux/macOS.
SSH Config File (~/.ssh/config)
The SSH config file is a powerful tool that lets you define connection presets, manage multiple keys, and configure advanced options. Instead of typing long SSH commands, you can create named aliases.
Basic Configuration Example
Create or edit ~/.ssh/config:
# ~/.ssh/config
# Personal server
Host myserver
HostName 203.0.113.50
User deploy
Port 22
IdentityFile ~/.ssh/id_ed25519
# Now connect with just:
# ssh myserver
# Instead of:
# ssh -i ~/.ssh/id_ed25519 deploy@203.0.113.50Using Multiple Keys for Different Services
If you use different keys for GitHub, GitLab, and your production servers:
# ~/.ssh/config
# GitHub (personal account)
Host github.com-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
IdentitiesOnly yes
# GitHub (work account)
Host github.com-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
# GitLab
Host gitlab.com
HostName gitlab.com
User git
IdentityFile ~/.ssh/id_ed25519_gitlab
IdentitiesOnly yes
PreferredAuthentications publickey
# Production server
Host production
HostName prod.example.com
User admin
Port 2222
IdentityFile ~/.ssh/id_ed25519_prod
IdentitiesOnly yes
# Usage:
# git clone git@github.com-personal:myuser/repo.git
# git clone git@github.com-work:company/repo.git
# ssh productionProxyJump: Connecting Through a Bastion Host
If you need to SSH through a jump server (bastion host) to reach an internal server:
# ~/.ssh/config
# Bastion / Jump host
Host bastion
HostName bastion.example.com
User jumpuser
IdentityFile ~/.ssh/id_ed25519
Port 22
# Internal server (accessed through bastion)
Host internal-server
HostName 10.0.1.50
User admin
IdentityFile ~/.ssh/id_ed25519
ProxyJump bastion
# Chained jump: client → bastion1 → bastion2 → target
Host deep-internal
HostName 10.0.2.100
User admin
ProxyJump bastion,bastion2Now you can connect directly with: ssh internal-server. SSH will automatically jump through the bastion host first.
Wildcard and Default Settings
Apply default settings to all connections:
# ~/.ssh/config
# Default settings for all hosts
Host *
AddKeysToAgent yes
IdentitiesOnly yes
ServerAliveInterval 60
ServerAliveCountMax 3
Compression yes
# Settings for all *.example.com hosts
Host *.example.com
User deploy
IdentityFile ~/.ssh/id_ed25519_work
Port 2222Useful SSH Config Options
IdentityFile: IdentityFile: Path to the private key to use.IdentitiesOnly: IdentitiesOnly yes: Only use the specified key, do not try others from the agent.ForwardAgent: ForwardAgent yes: Forward your local SSH agent to the remote server (use cautiously).ServerAliveInterval: ServerAliveInterval 60: Send a keep-alive packet every 60 seconds to prevent disconnection.ProxyJump: ProxyJump bastion: Route the connection through another SSH host.Port: Port 2222: Connect to a non-standard SSH port.
Add SSH Key to GitHub / GitLab
Using SSH keys with GitHub and GitLab is the recommended way to authenticate for Git operations. Here is how to set it up:
Step 1: Copy Your Public Key
Display and copy your public key:
# Linux / macOS
cat ~/.ssh/id_ed25519.pub
# macOS — copy directly to clipboard:
pbcopy < ~/.ssh/id_ed25519.pub
# Linux (with xclip):
xclip -selection clipboard < ~/.ssh/id_ed25519.pub
# Windows (PowerShell):
Get-Content ~/.ssh/id_ed25519.pub | Set-Clipboard
# Windows (Git Bash):
clip < ~/.ssh/id_ed25519.pubStep 2: Add the Key to GitHub
Step 3: Add the Key to GitLab
Step 4: Test the Connection
Verify that your SSH key is working:
# Test GitHub connection:
ssh -T git@github.comIf successful, you will see a message like:
Hi username! You've successfully authenticated, but GitHub does not provide shell access.For GitLab:
# Test GitLab connection:
ssh -T git@gitlab.com
# Expected output:
Welcome to GitLab, @username!Step 5: Clone Repositories Using SSH
Now you can clone repositories using the SSH URL instead of HTTPS:
# Clone via SSH (recommended):
git clone git@github.com:username/repository.git
# Instead of HTTPS:
# git clone https://github.com/username/repository.gitTo switch an existing repository from HTTPS to SSH:
# Check current remote URL:
git remote -v
# origin https://github.com/username/repo.git (fetch)
# Switch to SSH:
git remote set-url origin git@github.com:username/repo.git
# Verify:
git remote -v
# origin git@github.com:username/repo.git (fetch)SSH Agent: Managing Keys in Memory
The SSH agent is a background process that holds your private keys in memory so you do not have to enter your passphrase every time you use an SSH key. It is especially useful if your keys are protected with a passphrase (which they should be).
Start the SSH Agent
On Linux/macOS:
# Start the SSH agent in the background:
eval "$(ssh-agent -s)"
# Output: Agent pid 12345
# Add to your shell profile (~/.bashrc, ~/.zshrc) to start automatically:
if [ -z "$SSH_AUTH_SOCK" ]; then
eval "$(ssh-agent -s)" > /dev/null
fiOn Windows (PowerShell):
# PowerShell (run as Administrator to enable the service):
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
# Verify it is running:
Get-Service ssh-agent
# Status: RunningAdd Keys to the Agent
Add your private key to the agent:
# Add a specific key:
ssh-add ~/.ssh/id_ed25519
# Enter passphrase for /home/user/.ssh/id_ed25519:
# Identity added: /home/user/.ssh/id_ed25519 (your_email@example.com)
# Add RSA key:
ssh-add ~/.ssh/id_rsaAdd all default keys:
# Add all default keys (id_rsa, id_ed25519, etc.):
ssh-addList Keys in the Agent
View all keys currently loaded in the agent:
# List keys with fingerprints:
ssh-add -l
# 256 SHA256:abc123... your_email@example.com (ED25519)
# 4096 SHA256:def456... your_email@example.com (RSA)
# List keys with full public key:
ssh-add -LmacOS Keychain Integration
On macOS, you can store your SSH key passphrase in the system Keychain so it persists across reboots:
# Add key to macOS Keychain:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519Add this to your ~/.ssh/config to automatically load keys from the Keychain:
# ~/.ssh/config (macOS)
Host *
UseKeychain yes
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519Set Key Lifetime
For security, you can set a timeout so keys are automatically removed after a period of inactivity:
# Add key with 1-hour timeout:
ssh-add -t 3600 ~/.ssh/id_ed25519
# Add key with 8-hour timeout (workday):
ssh-add -t 28800 ~/.ssh/id_ed25519
# Remove all keys from the agent:
ssh-add -DAgent Forwarding
Agent forwarding lets you use your local SSH keys on a remote server without copying the keys there. Use it when you need to SSH from one server to another (e.g., pulling from GitHub on a deployment server):
# Forward agent for a single connection:
ssh -A user@server.example.com
# Or configure in ~/.ssh/config:
Host deploy-server
HostName deploy.example.com
User deploy
ForwardAgent yes
# On the remote server, you can now use your local keys:
# ssh -T git@github.com ← works without copying keys to the serverWarning: Warning: Agent forwarding exposes your keys to anyone with root access on the remote server. Only use it with servers you trust. Consider ProxyJump as a safer alternative.
SSH Key Passphrase
A passphrase adds a layer of encryption to your private key file. Even if someone steals your private key file, they cannot use it without the passphrase.
Why Use a Passphrase?
- Laptop theft: If your laptop is stolen, the passphrase prevents immediate access to your servers.
- Malware: If malware reads your ~/.ssh/ directory, encrypted keys are useless without the passphrase.
- Shared machines: If others have access to your user account, the passphrase is your last line of defense.
- Compliance: Many security standards (SOC 2, ISO 27001) require encrypted private keys.
Creating a Key with a Strong Passphrase
When generating a new key, ssh-keygen will prompt for a passphrase. Use a strong, unique passphrase:
# Generate key with increased KDF rounds for stronger passphrase protection:
ssh-keygen -t ed25519 -C "your_email@example.com" -a 100
# When prompted, use a strong passphrase:
# Good: correct-horse-battery-staple (4+ random words)
# Good: My$ecure_Key_2024!ForWork (mixed characters)
# Bad: password123 (too simple)
# Bad: qwerty (dictionary word)Change an Existing Key Passphrase
You can change (or add) a passphrase to an existing key without regenerating it:
# Change passphrase on an existing key:
ssh-keygen -p -f ~/.ssh/id_ed25519
# Output:
Enter old passphrase:
Enter new passphrase:
Enter same passphrase again:
Your identification has been saved with the new passphrase.Remove a Passphrase (Not Recommended)
If you need an unencrypted key (e.g., for automated scripts), you can remove the passphrase:
# Remove passphrase (enter empty string as new passphrase):
ssh-keygen -p -f ~/.ssh/id_ed25519
Enter old passphrase:
Enter new passphrase: # ← Press Enter (empty)
Enter same passphrase again: # ← Press Enter (empty)Warning: Warning: Keys without a passphrase are a significant security risk. For automated systems, consider using ssh-agent, deploy keys with limited permissions, or a secrets manager instead.
Increase KDF Rounds
The -a flag controls how many rounds of key derivation are applied to the passphrase. Higher values make brute-force attacks slower:
# Default KDF rounds: 16 (fast, less secure against brute-force)
ssh-keygen -t ed25519 -C "email@example.com"
# Increased KDF rounds: 100 (slower key loading, much harder to brute-force)
ssh-keygen -t ed25519 -C "email@example.com" -a 100
# High KDF rounds: 200 (very slow, maximum brute-force resistance)
ssh-keygen -t ed25519 -C "email@example.com" -a 200
# Note: KDF rounds affect how long it takes to decrypt the key
# with the passphrase, NOT the SSH connection speed.
# -a 100 adds ~1 second to key loading time.SSH Key Security Best Practices
File Permissions
Incorrect permissions are one of the most common SSH issues. SSH will refuse to use keys or config files with overly permissive permissions:
# If permissions are wrong, SSH will show errors like:
# "WARNING: UNPROTECTED PRIVATE KEY FILE!"
# "Permissions 0644 for '/home/user/.ssh/id_ed25519' are too open."
# "It is required that your private key files are NOT accessible by others."Set correct permissions:
# Set correct permissions for the .ssh directory:
chmod 700 ~/.ssh
# Set correct permissions for private keys:
chmod 600 ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_rsa
chmod 600 ~/.ssh/config
# Set correct permissions for public keys:
chmod 644 ~/.ssh/id_ed25519.pub
chmod 644 ~/.ssh/id_rsa.pub
# Set correct permissions for authorized_keys (server-side):
chmod 600 ~/.ssh/authorized_keys
# Set correct permissions for known_hosts:
chmod 644 ~/.ssh/known_hosts
# Verify all permissions at once:
ls -la ~/.ssh/
# drwx------ 2 user user 4096 Jan 15 10:30 .
# -rw------- 1 user user 464 Jan 15 10:30 id_ed25519
# -rw-r--r-- 1 user user 105 Jan 15 10:30 id_ed25519.pub
# -rw------- 1 user user 222 Jan 15 10:30 configRotate Keys Regularly
Key rotation limits the blast radius if a key is compromised. Best practices:
- Generate new keys at least once a year (or per your organization's policy).
- Add the new public key to all servers before removing the old one.
- Remove the old public key from authorized_keys after confirming the new key works.
- Revoke old keys from GitHub/GitLab/Bitbucket.
- Keep a record of when each key was generated and where it is deployed.
# Key rotation workflow:
# 1. Generate new key
ssh-keygen -t ed25519 -C "email@example.com-2025" -f ~/.ssh/id_ed25519_2025
# 2. Add new public key to server
ssh-copy-id -i ~/.ssh/id_ed25519_2025.pub user@server
# 3. Test new key works
ssh -i ~/.ssh/id_ed25519_2025 user@server
# 4. Remove old public key from server
ssh user@server "sed -i '/old_key_comment/d' ~/.ssh/authorized_keys"
# 5. Update local SSH config to use new key
# Edit ~/.ssh/config and change IdentityFile paths
# 6. Remove old local key files
rm ~/.ssh/id_ed25519_old ~/.ssh/id_ed25519_old.pubDisable Password Authentication on Servers
Once SSH key authentication is configured, disable password authentication to prevent brute-force attacks:
Edit /etc/ssh/sshd_config:
# /etc/ssh/sshd_config
# Disable password authentication
PasswordAuthentication no
# Disable challenge-response authentication
ChallengeResponseAuthentication no
# Disable PAM (optional, depends on your setup)
# UsePAM no
# Enable public key authentication (should be default)
PubkeyAuthentication yes
# Disable root login
PermitRootLogin no
# Allow only specific users
AllowUsers deploy adminRestart the SSH service:
# Debian / Ubuntu:
sudo systemctl restart sshd
# RHEL / CentOS / Fedora:
sudo systemctl restart sshd
# Older systems:
sudo service ssh restartWarning: Warning: Before disabling password authentication, make sure your SSH key login works. Otherwise, you may lock yourself out of the server.
Additional Security Measures
- Use a non-standard SSH port (e.g., Port 2222) to reduce automated scanning noise.
- Install fail2ban to block IP addresses with too many failed login attempts.
- Disable root login: set PermitRootLogin no in sshd_config.
- Use AllowUsers or AllowGroups to restrict which users can SSH in.
- Enable two-factor authentication (2FA) for an additional layer of security.
- Monitor /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (RHEL/CentOS) for suspicious activity.
Troubleshooting Common SSH Key Issues
Permission Denied (publickey)
This is the most common SSH error. It means the server rejected your key. Common causes and fixes:
# Fix: Specify the correct key explicitly
ssh -i ~/.ssh/id_ed25519 user@server.example.com
# Fix: Copy your public key to the server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server.example.com
# Or manually:
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
# Fix: Correct server-side permissions
ssh user@server "chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys""Permissions are too open" Error
If you see "WARNING: UNPROTECTED PRIVATE KEY FILE!" or "Permissions 0644 for 'id_ed25519' are too open", SSH is refusing to use the key because others can read it:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/user/.ssh/id_ed25519' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.Fix the permissions:
# Fix permissions:
chmod 600 ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_rsa
chmod 700 ~/.sshOn Windows, right-click the file > Properties > Security > Advanced, and remove all permissions except for your user account.
Debug SSH Connections
Use the -v, -vv, or -vvv flags for increasing levels of debug output:
# Verbose mode (increasing detail):
ssh -v user@server.example.com # Level 1: basic debug info
ssh -vv user@server.example.com # Level 2: more detail
ssh -vvv user@server.example.com # Level 3: maximum detail
# Example debug output (key parts):
debug1: Offering public key: /home/user/.ssh/id_ed25519 ED25519 SHA256:abc123...
debug1: Server accepts key: /home/user/.ssh/id_ed25519 ED25519 SHA256:abc123...
debug1: Authentication succeeded (publickey).Look for these key lines in the debug output:
"Offering public key": "Offering public key": Shows which keys SSH is trying."Server accepts key": "Server accepts key": Confirms the key was accepted."Authentication succeeded": "Authentication succeeded": Login was successful."No more authentication methods to try": "No more authentication methods to try": All offered keys were rejected.
Host Key Verification Failed
If the server's host key has changed (e.g., server rebuild), you will see a warning. Remove the old host key:
# Remove a specific host key:
ssh-keygen -R server.example.com
# Remove by IP address:
ssh-keygen -R 203.0.113.50
# Remove by IP and port:
ssh-keygen -R "[server.example.com]:2222"
# Then reconnect and accept the new host key:
ssh user@server.example.com
# The authenticity of host 'server.example.com' can't be established.
# ED25519 key fingerprint is SHA256:xyz789...
# Are you sure you want to continue connecting (yes/no)? yesWarning: Warning: Only do this if you expect the host key to have changed (e.g., server rebuild). An unexpected change could indicate a man-in-the-middle attack.
Connection Timed Out
- Verify the server is running and accepting connections on the correct port.
- Check firewalls (ufw, iptables, or cloud security groups).
- Try connecting with a specific port: ssh -p 2222 user@server.
- Add ServerAliveInterval to your SSH config to prevent idle disconnections.
# Test connectivity:
ssh -v -o ConnectTimeout=10 user@server.example.com
# Check if the port is open:
nc -zv server.example.com 22
# or
telnet server.example.com 22
# Add keep-alive to prevent idle timeout (~/.ssh/config):
Host *
ServerAliveInterval 60
ServerAliveCountMax 3Frequently Asked Questions
Should I use Ed25519 or RSA for SSH keys?
Use Ed25519 for all new SSH keys. Ed25519 provides equivalent or better security than RSA-4096 with significantly smaller key sizes (32 bytes vs ~512 bytes for the public key), faster signing and verification, and resistance to certain implementation attacks. Only use RSA-4096 if you need compatibility with very old systems (pre-2014) that do not support Ed25519.
Is it safe to use SSH keys without a passphrase?
SSH keys without a passphrase are a significant security risk. If your private key file is ever compromised (laptop theft, malware, backup exposure), the attacker gets immediate access to all servers that trust that key. Always use a strong passphrase and rely on ssh-agent to avoid typing it repeatedly. For automated systems, use deploy keys with minimal permissions or a secrets manager.
How do I use multiple SSH keys for different GitHub accounts?
Create a separate key for each account and configure ~/.ssh/config with different Host aliases. For example, set Host github-personal with HostName github.com and IdentityFile ~/.ssh/id_ed25519_personal, and Host github-work with IdentityFile ~/.ssh/id_ed25519_work. Then clone using the alias: git clone git@github-personal:user/repo.git.
What do I do if my SSH private key is compromised?
Immediately remove the compromised public key from all servers (authorized_keys), GitHub, GitLab, and any other services. Generate a new key pair and deploy the new public key. Audit logs for any unauthorized access during the period the key may have been compromised. If the key was used for production servers, consider a full security audit.
Can I convert an RSA key to Ed25519?
No, you cannot convert between key algorithms. You must generate a new Ed25519 key pair with ssh-keygen -t ed25519 and then add the new public key to your servers and services (GitHub, GitLab, etc.). You can keep the old RSA key as a backup while transitioning, then remove it once the new Ed25519 key is deployed everywhere.