Skip to main content
โšก Calmops

SSH Passwordless Login: Key-Based Authentication Setup

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). Use rsa -b 4096 for 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

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.

Resources

Comments