A key pair replaces the password with two files: a private key that stays on your machine and a public key that goes on the server. A key can’t be guessed the way a password can, and a server that accepts only keys shuts out the bots that scan port 22 and try common passwords. The order matters here: the key has to work before passwords are turned off, or the next login fails.
Create a key on your machine
Run this on the computer you connect from, not on the server. Ed25519 keys are short, fast to check, and supported by every OpenSSH release since 6.5. The comment after -C is only a label, so put something in it that tells you later where the key lives.
$ ssh-keygen -t ed25519 -C "you@laptop, 2026-10"Generating public/private ed25519 key pair.# trimmed: the prompts for the file name and the passphraseYour identification has been saved in /home/you/.ssh/id_ed25519Your public key has been saved in /home/you/.ssh/id_ed25519.pub
Give the key a passphrase. Without one, anybody who copies id_ed25519 off your laptop can log in as you. With one, the file is encrypted, and ssh-add loads it into the agent once per session so you don’t type the passphrase on every connection.
| File | What it is | Where it goes |
|---|---|---|
~/.ssh/id_ed25519 | The private key | Stays on your machine, mode 600. Never copy it to a server. |
~/.ssh/id_ed25519.pub | The public key, one line of text | Into ~/.ssh/authorized_keys on every server you log in to |
Install the public key on the server
ssh-copy-id logs in with your password one last time and appends the public key to ~/.ssh/authorized_keys on the server, creating the directory with the right permissions if needed.
$ ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]# trimmed: the INFO lines and the password promptNumber of key(s) added: 1
Windows doesn’t ship ssh-copy-id. From any machine without it, pipe the key into the same file yourself:
$ cat ~/.ssh/id_ed25519.pub | ssh [email protected] 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'Test the key in a second session
Keep the session you already have open, and open a second terminal. These options make the client try the key and nothing else, so a silent fallback to the password can’t make a broken key look like it works:
$ ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no [email protected]$ ssh -v [email protected] true 2>&1 | grep Authenticateddebug1: Authenticated to 192.0.2.10 ([192.0.2.10]:22) using "publickey".
If the first command asks for a password or ends in Permission denied, fix the key before you go on.
Turn password login off
On all three distributions, an Include line near the top of /etc/ssh/sshd_config reads every file in /etc/ssh/sshd_config.d/ ending in .conf, in alphabetical order. For each setting, sshd keeps the first value it reads and ignores the rest. A setting further down in sshd_config loses to any drop-in file, and a drop-in file loses to one that sorts before it.
That’s why the file below starts with 10-. Ubuntu cloud images and other cloud-init installs often have /etc/ssh/sshd_config.d/50-cloud-init.conf with PasswordAuthentication yes in it. Edit sshd_config alone and that line keeps passwords on.
Write the drop-in file
/etc/ssh/sshd_config.d/10-keys-only.conf# Keys only. Sorts before 50-cloud-init.conf, so these values win.PasswordAuthentication noKbdInteractiveAuthentication noPermitRootLogin prohibit-password
KbdInteractiveAuthenticationcloses the second way a password can be asked for (through PAM). On OpenSSH before 8.7 it was calledChallengeResponseAuthentication.prohibit-passwordlets root in with a key only, which is the default since OpenSSH 7.0. Set it tonoif nobody logs in as root at all.Check the configuration
shell$ sudo sshd -t$ sudo sshd -T | grep -i passwordauthenticationpasswordauthentication no
sshd -tprints nothing when the files are valid.sshd -Tprints the values sshd will use after reading every file, so it shows whether another drop-in still wins.Reload sshd
shell# Debian and Ubuntu$ sudo systemctl reload ssh# RHEL 9$ sudo systemctl reload sshd
A reload applies to connections made after it. The session you’re typing in stays open.
Prove that passwords are refused
shell$ ssh -o PubkeyAuthentication=no [email protected][email protected]: Permission denied (publickey).
The list in brackets is what the server still accepts.
publickeyalone is the result you want. On RHEL it also lists the GSSAPI methods that50-redhat.confturns on.
Next steps
- Remove keys nobody uses from
~/.ssh/authorized_keys. Every line in it is a way in. - Keep host names, users, and keys in one place on your machine: Use an SSH config file and jump hosts.
Last checked on 24 October 2026 against OpenSSH 9.2 (Debian 12), OpenSSH 9.6 (Ubuntu 24.04), and OpenSSH 8.7 (RHEL 9). If a step doesn’t match what you see, contact us with the command and what it printed.