Password login is the weakest spot of a new server: within minutes of going online, bots start brute-forcing passwords on the SSH port. SSH key authentication cannot be brute-forced, and you no longer have to type a password. This guide covers the whole path: generate a key, put it on the server, test it, and only then disable password authentication.
Tested on Ubuntu 24.04, Ubuntu 26.04 and Debian 12 (server side). Replace 203.0.113.10 with your server's address and root with your user.
How SSH key authentication works
A key is a pair of files. The private key stays on your computer and is never shared. The public key (the file ending in .pub) goes to the server, into ~/.ssh/authorized_keys. When you connect, the server verifies that you hold the private key matching that public key; the private key itself never travels over the network.
Step 1. Generate an SSH key
Windows 10 and 11 ship with the OpenSSH client, so the commands are the same; run them in PowerShell. On macOS and Linux, use the terminal:
ssh-keygen -t ed25519 -C "laptop-john"
-t ed25519is a modern key type: short and strong. Old systems that do not support it are rare today.-Cis a comment that tells you later whose key this is. The computer name works well.
The program asks where to save the key. Press Enter to keep the default path (~/.ssh/id_ed25519, on Windows C:\Users\<name>\.ssh\id_ed25519). Then it asks for a passphrase: it encrypts the private key on disk, so if your laptop is stolen, the key cannot be used. Set one.
Step 2. Copy the public key to the server
macOS and Linux
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@203.0.113.10
The command asks for the server password once and appends the key to ~/.ssh/authorized_keys for you.
Windows
Windows has no ssh-copy-id, so do the same with a single PowerShell command:
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh root@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
Manually
If you prefer to do it by hand, open id_ed25519.pub on your computer, copy the entire single line (it starts with ssh-ed25519) and run on the server:
mkdir -p ~/.ssh && chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys # paste the line, save: Ctrl+O, Enter, Ctrl+X
chmod 600 ~/.ssh/authorized_keys
Step 3. Test SSH key login
ssh root@203.0.113.10
If the server no longer asks for its password (it may ask for the key passphrase, which is expected), you are done. If it still asks for the server password, the key was not picked up; see the troubleshooting section below.
Step 4. Set up a short host alias in ~/.ssh/config
To avoid typing the address, port and key path every time, add this to ~/.ssh/config on your computer (on Windows, C:\Users\<name>\.ssh\config):
Host myserver
HostName 203.0.113.10
User root
IdentityFile ~/.ssh/id_ed25519
Now ssh myserver is enough. If you change the SSH port later, add a Port <number> line. Other ~/.ssh/config options, copying files and fixing connection errors are covered in How to connect to a server over SSH.
Step 5. Disable SSH password authentication
Do this only after confirming in step 3 that key login works, and keep your current session open until you finish testing: if something goes wrong, you can revert everything through it.
On the server, create a separate config file:
sudo tee /etc/ssh/sshd_config.d/00-keys-only.conf > /dev/null <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
EOF
Why a separate file with the 00 prefix: SSH uses the first value it finds for each option and reads the files in sshd_config.d in alphabetical order. Cloud images often include 50-cloud-init.conf with PasswordAuthentication yes; our file is read first and wins. PermitRootLogin prohibit-password allows root to log in with a key only.
Validate the configuration and apply it:
sudo sshd -t # no output means no errors
sudo sshd -T | grep -E 'passwordauthentication|kbdinteractive|permitrootlogin'
sudo systemctl reload ssh # on AlmaLinux and CentOS the service is called sshd
sshd -T should show passwordauthentication no and kbdinteractiveauthentication no. For root, Ubuntu 24.04 and Debian 12 print permitrootlogin without-password, which is the old name of the same prohibit-password value. Now connect again in a new terminal window: key login should work. A password login attempt should be rejected:
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password root@203.0.113.10
# root@203.0.113.10: Permission denied (publickey).
SSH key login not working: troubleshooting
Connect with verbose output; it almost always shows the cause:
ssh -v root@203.0.113.10
Common causes:
| Symptom | Cause and fix |
|---|---|
Permission denied (publickey) right after setup |
The key is in the wrong file or under the wrong user. Check ~/.ssh/authorized_keys of the exact user you log in as |
| The key is in place, but the server ignores it | Permissions are too open. You need chmod 700 ~/.ssh, chmod 600 ~/.ssh/authorized_keys, and the home directory must not be writable by others |
The -v output has no Offering public key line |
The client did not find the key. Specify it explicitly with ssh -i ~/.ssh/id_ed25519 … or add IdentityFile to ~/.ssh/config |
| Password login is off and the key does not work | Log in through the server's web console in your hosting control panel, delete /etc/ssh/sshd_config.d/00-keys-only.conf and run sudo systemctl reload ssh |
Next steps
- Use a separate key for each computer: if you lose a laptop, you only need to delete one line from
authorized_keys. - Do not send your private key over messengers or keep it in cloud folders without encryption.
- The next layer of protection is a firewall and automatic blocking of brute-force attempts: initial server setup on Ubuntu (in Russian).
- A separate key with limited permissions for automated deployment is covered in the article on deploying from GitHub Actions (in Russian).