How to Set Up SSH Key Authentication (2026)

To set up SSH key authentication you generate a key pair on your own machine, copy the public half to the server’s authorized_keys file, and confirm it works before you touch any server settings. Once that check passes, you can log in with ssh user@host and never type a password again.

It takes about ten minutes on a machine you already have admin access to, and almost all the pain comes from file permissions rather than the cryptography itself. The commands below are identical on Linux and macOS, with a PowerShell variant for Windows 10 and 11.

How to Set Up SSH Key Authentication (Step-by-Step)
Table of Contents

What You Need

Four things, and you probably already have three of them.

  • An SSH client. OpenSSH ships with Linux, macOS and Windows 10/11 (Settings, System, Optional features). PuTTY works too if you prefer a GUI.
  • A terminal. Terminal.app or iTerm2 on macOS, GNOME Terminal or Konsole on Linux, Windows Terminal or PowerShell on Windows.
  • A user account on the remote server with a password that still works, plus sudo if you plan to edit sshd_config.
  • The server address and username exactly as the provider spelled them, including any non-standard port.

Check your client before anything else. On Linux and macOS this prints the client version:

ssh -V

On Windows 11, PowerShell reports the same thing once the client is installed:

ssh -V

If that command is missing on Windows, open Settings, System, Optional features, then View features, and add OpenSSH Client. One thing worth knowing: any OpenSSH version from 6.5 onward, which covers Debian 8 and CentOS 7 and everything shipped since, supports ed25519 keys. You do not need a newer server.

Step-by-Step

How to set up ssh key authentication comes down to six ordered steps, and the order matters more than the individual commands. Get the key working first, verify it from a second terminal, and only then harden the server.

Step-by-Step

Step 1: Generate an SSH Key Pair

Run ssh-keygen on your own machine, not on the server. This creates two files: id_ed25519, the private key that must never leave your machine, and id_ed25519.pub, the public key you hand out freely.

ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519

What each flag does: -t ed25519 picks the algorithm, -C attaches a comment so you can identify the key later, and -f sets the path. You will be prompted for a passphrase, and I would set one on any machine that leaves your desk. Type it twice; if the two entries do not match you will be asked again.

Long-time Unix users often just run ssh-keygen and accept every default, which lands on ed25519 these days. Either way is fine, though a passphrase only protects the key at rest, so back the private file up somewhere safe if the machine dies.

To confirm both files exist:

ls -l ~/.ssh/id_ed25519*
# -rw-------  1 you  staff  411 ... id_ed25519
# -rw-r--r--  1 you  staff  102 ... id_ed25519.pub

On Windows PowerShell, ssh-keygen -t ed25519 -f "$env:USERPROFILE.sshid_ed25519" does the same job and stores the pair under your user profile.

If your server is genuinely ancient and rejects ed25519, fall back to RSA:

ssh-keygen -t rsa -b 4096 -C "[email protected]" -f ~/.ssh/id_rsa
TypeKey sizeUse it when
ed25519256-bitDefault choice. Fast, small, supported by OpenSSH 6.5 and later.
ECDSA256 or 521-bitYou want smaller keys in AMIs or images, or a client that lacks ed25519.
RSA4096-bitLegacy clients only. Recent OpenSSH logs deprecation warnings for RSA.
DSA1024-bitDo not use. Removed from default policy in modern OpenSSH.

One community thread on itsfoss.community makes the RSA point well: a member had generated with -t rsa -b 4096 for years, then realised the deprecation warnings he kept seeing in /var/log/auth.log were about his own key, not about failed logins. He switched to -t ed25519 and logged in fine on Ubuntu 24.04 LTS with OpenSSH 9.6p1 at both ends.

Step 2: Copy the Public Key to the Server

Where ssh-copy-id exists, it does the work in one line:

ssh-copy-id [email protected]
# for a non-standard port:
ssh-copy-id -p 2222 [email protected]

It prompts for the password once, appends the public key to authorized_keys, and sets the permissions it knows about.

On Windows 10 and 11 OpenSSH there is no ssh-copy-id. Print the key instead and paste it through the provider’s web console, which is the safest route on a machine that has no password auth left:

Get-Content $env:USERPROFILE.sshid_ed25519.pub | Set-Clipboard

On Linux and macOS:

cat ~/.ssh/id_ed25519.pub

Never transfer the private key. If a tool or a person asks for id_ed25519 without the .pub suffix, stop.

Step 3: Install the Key in authorized_keys

The server keeps your public key in a plain text file called authorized_keys, one key per line, inside the remote user’s ~/.ssh directory. For the user deploy the full path is /home/deploy/.ssh/authorized_keys.

If ssh-copy-id was unavailable, log in with your password and build the file by hand:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
cat >> ~/.ssh/authorized_keys
# paste the whole public key line, then press Ctrl+D

To create the file non-interactively in one shot:

echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... [email protected]' >> ~/.ssh/authorized_keys

Three mistakes corrupt this file more than anything else: a missing newline at the end, Windows CRLF line endings carried over from Notepad, and a stray $ or > from the shell prompt ending up inside the pasted line. If two keys are on the same line, neither works.

Windows OpenSSH servers use the same layout, with the path usually C:Users<name>.sshauthorized_keys. A few network appliances are different: MikroTik routers and CoreELEC boxes keep their keys under /storage/.ssh/authorized_keys, and refuse keys pasted anywhere else even after a restart.

Step 4: Fix File and Directory Permissions

OpenSSH refuses to read a key file that other users can write to, and it does so silently: you get Permission denied (publickey) with no explanation. This is the most commonly reported cause of failed key authentication, and the fix is three commands.

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R "$USER":"$USER" ~/.ssh

On the server, the same ownership has to apply to the remote user, run as root:

chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
PathRequired modeWhat breaks if it is wrong
Home directory755 or stricterKey rejected: sshd will not traverse a world-writable home
~/.ssh700Key rejected, StrictModes blocks the read
~/.ssh/authorized_keys600Key rejected, or ignored entirely if group-writable
~/.ssh/id_ed25519 (private)600The client refuses to use the key

On Windows there are no chmod bits; ACLs do the same job. For a local user, removing inherited access to the .ssh folder is what the server expects:

icacls $env:USERPROFILE.ssh /inheritance:r
icacls $env:USERPROFILE.ssh /grant "$env:USERNAME:(F)"

If you have SELinux in enforcing mode, correct modes are not enough. The file needs the right context, which restorecon -R -v ~/.ssh will reapply.

Step 5: Test SSH Key Authentication

Test with a password still enabled, so a failure costs you nothing. Keep your existing session open while you do it.

ssh -i ~/.ssh/id_ed25519 [email protected]
# non-standard port:
ssh -p 2222 -i ~/.ssh/id_ed25519 [email protected]

A success looks like this: no password prompt, and the verbose output names the method it used.

ssh -v [email protected] 2>&1 | grep -i "authentication succeeded"
# debug1: Authentication succeeded (publickey).

If you see Authentications that can continue: publickey instead, the server never offered password auth, which means it did not like the key. When the line is missing entirely, fall back to the full verbosity setting and read it top to bottom:

ssh -vvv [email protected]

What to look for, in order: which key files were offered (Offering public key: /home/you/.ssh/id_ed25519), whether the server accepted it (Server accepts key), and which method finally won. Server-side, journalctl -u ssh on systemd hosts or tail -f /var/log/auth.log on Debian and RHEL systems gives the matching reason. Running /usr/sbin/sshd -ddd on a spare port is the last resort, and it tells you outright why it will not use your authorized_keys file.

Once the key works, cache it in the agent so the passphrase is typed once per session:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE.sshid_ed25519

A config file entry saves you typing the path and port forever:

cat >> ~/.ssh/config <<'EOF'
Host app01
    HostName server.example.com
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes
EOF

Now ssh app01 is all you need. For a server behind a bastion, add ProxyJump [email protected] to the same block.

Step 6: Disable Password Authentication Safely

This is the step that locks people out. Only reach it after the key login has worked in a second terminal, with your original session still open.

Back up the config first, so you can restore it from the console if something is wrong:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

Then set the three directives that matter:

sudo nano /etc/ssh/sshd_config
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin prohibit-password

PermitRootLogin prohibit-password keeps root reachable by key while closing it to password guessing. On cloud images the file may be split across /etc/ssh/sshd_config.d/*.conf, and a drop-in file will win over the main config, so check there too.

Validate before restarting, then reload rather than restart so live sessions survive:

sudo sshd -t && sudo systemctl reload sshd
# Debian and Ubuntu use ssh.service, RHEL and Fedora use sshd.service

Open a brand new terminal and confirm your key still logs you in. Only close the original session once that succeeds.

Common Mistakes

ErrorLikely causeFix
Permission denied (publickey)Loose permissions on ~/.ssh or authorized_keyschmod 700 ~/.ssh and chmod 600 authorized_keys on the server
Permission denied (publickey)Private key pasted by mistake instead of the public oneRemove the line, append the output of cat id_ed25519.pub
Permission denied (publickey)Wrong username, or the key is in root’s file not the user’sCheck AuthorizedKeysFile in sshd_config and who owns the file
Bad permissions, please try againThe client refuses the private key locallychmod 600 on the private key, or re-add it with ssh-add
Too many authentication failuresAgent offering five keys before the right oneAdd IdentitiesOnly yes to the Host block
Connection refused after a rebootsshd config broken by the hardening stepRestore sshd_config.bak from the provider console
fatal: could not read from remote repositoryGit using SSH without a registered public keyAdd id_ed25519.pub to the repository’s deploy keys, then ssh -T git@host

That last one is what permission denied (publickey), fatal: could not read from remote repository usually means: Git got as far as the server and was refused. Add the same public key to GitHub or GitLab under Settings, SSH and GPG keys, then verify with ssh -T [email protected] before retrying the clone.

Two more worth knowing. If key login works for your user but not for root, check PermitRootLogin and remember root’s authorized_keys lives in /root/.ssh, owned by root. And if authentication worked yesterday but broke after a package upgrade, look for an algorithm that is no longer accepted: DSA and small RSA keys get disabled by OpenSSH policy, so an ed25519 replacement is usually the fix.

Frequently Asked Questions

Which SSH key type should I use in ssh-keygen?

Use ed25519 unless you have a specific reason not to. It is fast, produces short keys, and any OpenSSH server from 6.5 onward accepts it. Choose ECDSA 521 for clients that predate ed25519 support. Reserve RSA 4096 for genuinely old equipment, since current OpenSSH versions log deprecation warnings for RSA keys. DSA is no longer accepted by default.

How do I fix Permission denied (publickey)?

Run ssh -vvv to see which keys were offered, then fix permissions on the server: chmod 700 on the user’s .ssh directory, chmod 600 on authorized_keys, and chown both to that user. Confirm the line in authorized_keys starts with ssh-ed25519 and ends with a newline. If you pasted the private key by mistake, replace it with the output of cat ~/.ssh/id_ed25519.pub.

Why do my SSH keys still ask for a password?

Usually the server never accepted the key, so ssh falls back to whatever other methods are allowed. Causes include loose permissions, a public key that was never appended to authorized_keys, a mismatched username, or several keys in the agent with IdentitiesOnly unset. Check ssh -vvv for the line reporting which key was offered, and read the server log for the refusal reason.

Can I use the same key for several servers and for Git?

Yes, and it is normal practice. Copy the public key to every server’s authorized_keys file, and register the same public key in GitHub or GitLab under SSH and GPG keys. Keep one key per device rather than one key everywhere, so you can revoke a single machine without touching the rest of your infrastructure.

Should I disable password authentication after setting up keys?

Only after key login works, verified in a second terminal with your original session still open. Set PubkeyAuthentication yes, PasswordAuthentication no and PermitRootLogin prohibit-password in sshd_config, run sshd -t to validate, then reload the service. If you lock yourself out, restore sshd_config.bak from your provider’s console.

How do I use SSH keys on Windows?

Windows 10 and 11 include the OpenSSH client, so install it from Optional features and use PowerShell. Generate a pair with ssh-keygen -t ed25519, copy the public key with Get-Content, then paste it into the server’s authorized_keys file. PuTTY is the alternative: puttygen creates .ppk files instead, which OpenSSH cannot read, so do not mix the two formats on one key.

What to do next

Run the whole thing once without any existing keys: generate with ssh-keygen -t ed25519, copy with ssh-copy-id, set 700 and 600, then test. Everything after that is refinement.

Once key auth works, three habits keep it working. Add a Host block per server so you type ssh app01 instead of a full command line. Add the passphrase to ssh-agent so it is asked once per login session. And when a machine is lost or decommissioned, delete its key line from authorized_keys on each server, which revokes it immediately with no change needed on the client.

Leave a Comment