SSH Key Authentication Setup - Passwordless and Secure Login

SSH Key Authentication Setup - Passwordless and Secure Login

What you'll be able to do

  • Generate an ED25519 key pair, deploy the public key, and log in without a password
  • Set the right permissions under `~/.ssh` and diagnose `Permission denied (publickey)` yourself
  • Manage multiple servers and passphrases with `~/.ssh/config` and `ssh-agent`

Prerequisites (read these first)

What This Article Covers

  • How to generate an SSH key pair and connect to a server
  • How to deploy your public key correctly with ssh-copy-id
  • How to manage multiple servers with ~/.ssh/config

Terms used in this article (defined up front)

  • Key pair: two matching files. The public key (the one ending in .pub) and the private key (the one without .pub) form one set
  • Public key: the key you place on the server. It is safe for others to see
  • Private key: the key that stays on your own machine. It must never reach anyone else. Also called an "identity file"
  • Passphrase: the secret that encrypts the private key file itself. It is not the server login password — these two are easy to confuse, so keep them apart
  • authorized_keys: the file on the server listing every public key allowed to log in as that user. It lives at ~/.ssh/authorized_keys
  • ssh-agent: a background program that holds your decrypted private key in memory so you do not retype the passphrase
  • ED25519 / RSA: names of key algorithms. ED25519 is the current recommendation

Quick Summary (3 Steps)

  1. Run ssh-keygen -t ed25519 to generate a key pair
  2. Run ssh-copy-id user@server to deploy the public key
  3. Run ssh user@server — no password needed

Prerequisites

  • Ubuntu / Debian / RHEL-based Linux on both client and server
  • OpenSSH installed on both machines
  • Initial access to the server via password authentication

Why Use Key Authentication?

Key authentication is more secure than passwords and removes manual input from automation. There are three main reasons to switch.

  • Security: Your private key never leaves your local machine. No password is sent over the network.
  • Brute-force resistance: With a long enough key, trying every combination is infeasible.
  • Automation: rsync, Ansible, and CI/CD pipelines can connect where nobody is there to type a password.

1. Generate a Key Pair

Which algorithm should you use?

ED25519 is the current recommendation. It gives you strength on par with (or above) RSA-4096 from a far shorter key and faster operations. Fall back to -t rsa -b 4096 only for older devices that cannot handle ED25519.

ssh-keygen -t ed25519 -C "your_email@example.com"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub

The -C flag adds a comment (useful for identification). It is optional.

Why set a passphrase?

A passphrase encrypts the private key file itself. Even if your machine is stolen, the key cannot be used as is. Use ssh-agent to avoid retyping the passphrase on every connection (see below). You can press Enter to leave it empty, but then anyone who obtains the private key file can log in straight away.

Verify the generated files:

ls -la ~/.ssh/
total 16
drwx------ 2 user user 4096 May 31 10:00 .
drwxr-xr-x 8 user user 4096 May 31 10:00 ..
-rw------- 1 user user  419 May 31 10:00 id_ed25519
-rw-r--r-- 1 user user  107 May 31 10:00 id_ed25519.pub
  • id_ed25519 (private key): permissions 600. This file stays on your own machine.
  • id_ed25519.pub (public key): the one you append to ~/.ssh/authorized_keys on the server.

2. Deploy the Public Key to the Server

Use ssh-copy-id (recommended)

Run this once while password authentication is still active on the server. The password it asks for is the server login password, not the key passphrase.

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s)
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed
user@server's password:
Number of key(s) added: 1

ssh-copy-id appends the public key to ~/.ssh/authorized_keys on the server. Existing keys are appended to, never overwritten. If it has to create ~/.ssh, it creates it with the right permissions — but it does not fix permissions on a directory or file that already exists. Always run the permission check in the next section.

Manual deployment when ssh-copy-id is unavailable

cat ~/.ssh/id_ed25519.pub | ssh user@server \
  "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

3. Set Correct Permissions

SSH rejects key authentication when directory or file permissions are too permissive. The reasoning: a key stored where others can read or write it cannot be trusted.

Path Required Permission Reason
~/.ssh/ 700 Owner read/write/execute only
~/.ssh/authorized_keys 600 Owner read/write only
~/.ssh/id_ed25519 600 Private key must be strictly protected
~/.ssh/id_ed25519.pub 644 Public key is safe for others to read

Fix commands:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519

4. Test the Connection

ssh -v user@server

The -v flag (verbose) prints the authentication process in detail. It shows which key was offered and whether the server accepted it.

...
debug1: Offering public key: /home/user/.ssh/id_ed25519 ED25519 SHA256:xxxxx
debug1: Server accepts key: /home/user/.ssh/id_ed25519 ED25519 SHA256:xxxxx
Authenticated to server ([x.x.x.x]:22) using "publickey".

Authenticated to server ... using "publickey" confirms key authentication is working.

Disable password authentication only after key login is proven

Do not set PasswordAuthentication no in /etc/ssh/sshd_config until key authentication reliably works. Disable it while the key is misplaced and you end up with a server nobody can log into.

The safe sequence

  1. Keep your current SSH session open. Do not close it
  2. From a second terminal, open a new session and confirm the key login works
  3. Only then change the setting and run sudo systemctl reload ssh (sshd on RHEL-family systems)
  4. Confirm login works from yet another new session before closing the first one

Troubleshooting

Symptom: Permission denied (publickey)

Check 1: is a key being offered at all?

ssh -v user@server 2>&1 | grep -i "offering\|authentications that can continue"

If none is offered, name the key explicitly with ssh -i ~/.ssh/id_ed25519 user@server, or check IdentityFile in ~/.ssh/config.

Check 2: permissions on the private key, client side

ls -l ~/.ssh/id_ed25519

Anything other than -rw------- (600) needs chmod 600 ~/.ssh/id_ed25519.

Check 3: permissions and contents on the server

ssh user@server 'ls -ld ~ ~/.ssh; ls -l ~/.ssh/authorized_keys; wc -l ~/.ssh/authorized_keys'

If the home directory, ~/.ssh, or authorized_keys is writable by group or others, sshd ignores the key.

Fix

  1. Bring the permissions back to 700 / 600
  2. Run ssh-copy-id again
  3. If it still fails, read the reason on the server with sudo journalctl -u ssh -n 30 (-u sshd on RHEL-family systems)

5. Manage Connections with ~/.ssh/config

Once you have more than a couple of hosts, use ~/.ssh/config. It lets you save a hostname, username, and key file under one short alias.

vim ~/.ssh/config

Example configuration:

Host myserver
    HostName 192.168.1.100
    User ubuntu
    IdentityFile ~/.ssh/id_ed25519
    Port 22

Host staging
    HostName staging.example.com
    User deploy
    IdentityFile ~/.ssh/id_ed25519

After saving, connect with just ssh myserver.

chmod 600 ~/.ssh/config

If ~/.ssh/config is writable by group or others (664, for instance), ssh prints Bad owner or permissions on /home/user/.ssh/config and aborts the connection — it does not quietly carry on. Keep it at 600.

6. Manage Passphrases with ssh-agent

ssh-agent holds your decrypted key in memory so you type the passphrase only once per session. The key lives in memory only and is gone when you log out.

# Start the agent
eval "$(ssh-agent -s)"

# Add your key (enter passphrase once)
ssh-add ~/.ssh/id_ed25519
Identity added: /home/user/.ssh/id_ed25519 (your_email@example.com)

List registered keys:

ssh-add -l

On macOS, the system Keychain integrates with ssh-agent. Add UseKeychain yes and AddKeysToAgent yes to ~/.ssh/config to persist keys across reboots.

Summary

Command Purpose
ssh-keygen -t ed25519 Generate key pair (ED25519)
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server Deploy public key to server
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys Fix directory and file permissions
ssh -v user@server Test connection with verbose output
eval "$(ssh-agent -s)" && ssh-add Cache passphrase for the session

Next Reading

Share this article

Next steps