Turning off SSH password authentication without locking yourself out

Keys-only is the strongest single change you can make to an exposed SSH server. The safe order to do it in, the config lines that actually matter, and what it does not fix.

7 min read

Why this is the highest-value change

Almost every compromise of an internet-facing Linux server begins with a valid password — guessed, reused from someone else's breach, or phished. Disable password authentication and that entire category stops being possible. Not harder: impossible. There is no password to guess.

Nothing else on a hardening list comes close for the effort involved. It is two lines of configuration and a reload.

The reason people postpone it is the risk of doing it wrong, and that risk is real: get the order wrong and you disconnect yourself from a machine you reach only over SSH. The rest of this guide is that order.

The safe sequence

Every step below is verified before the next one is taken, and the session you are in stays open throughout. Do not close it until the very end.

First, generate a key if you do not have one. Ed25519 is the current default: shorter, faster and at least as strong as a 4096-bit RSA key.

bash
# 1. On your own machine, not the server
ssh-keygen -t ed25519 -C "you@example.com"

# 2. Copy the public key to the server (asks for your password one last time)
ssh-copy-id user@server

# 3. Verify from a SECOND terminal, without closing the first
ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no user@server

The configuration that actually matters

Only after step 3 succeeds, edit the server's configuration. On modern distributions the file to edit may not be sshd_config itself: many ship a /etc/ssh/sshd_config.d/ directory whose files are included and can override what you write above.

Four settings do the work:

bash
# /etc/ssh/sshd_config.d/10-hardening.conf   (or sshd_config directly)
PasswordAuthentication no
KbdInteractiveAuthentication no    # older name: ChallengeResponseAuthentication
PermitRootLogin prohibit-password  # or 'no' if root never logs in directly
PubkeyAuthentication yes

# Always test the config before reloading — this catches typos that
# would otherwise stop sshd from coming back at all:
sudo sshd -t

# Then reload rather than restart: existing sessions survive
sudo systemctl reload ssh    # or 'sshd' on the RHEL family

Verifying it took effect

Do not trust the config file — ask sshd what it actually resolved to. sshd -T prints the effective configuration after all includes and overrides:

bash
sudo sshd -T | grep -iE 'passwordauthentication|kbdinteractiveauthentication|permitrootlogin'
# expected:
#   passwordauthentication no
#   kbdinteractiveauthentication no
#   permitrootlogin prohibit-password

# And prove it from outside: this must now be refused
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password user@server

What it does not fix

Keys-only removes the risk of guessing. It does not remove the traffic, and it does not remove every path in.

The bots keep connecting. They do not know your configuration, so they keep offering passwords and keep being rejected — each attempt still costing a TCP connection, an sshd fork and a log line. Your auth log still fills with noise, and the one event you needed still ages out. Something still has to block the sources.

And a private key is a file. On a laptop that gets stolen, in a repository someone committed by accident, in a CI runner's environment. Protect keys with a passphrase, keep them off shared machines, and rotate them when someone leaves — a leaked key is exactly as bad as a leaked password.

It also does nothing about an unpatched sshd, an exposed service on another port, or a vulnerable application running on the same host. It is the single best change available, and it is one control among several.

The companion piece

With passwords off, the remaining job is the volume. SSH Protector reads the same auth stream, bans the sources that keep arriving — by subnet, permanently, restored on boot — and whitelists your own address before anything is blocked.

It detects the real SSH port from sshd's configuration rather than assuming 22, so a server you have already moved off the default is covered without configuring anything.

Keys-only for the risk. Source banning for the load, and for the readable log that lets you notice the one event that matters.

FAQ

How do I disable SSH password authentication safely?
Generate a key, copy it with ssh-copy-id, then verify from a second terminal that key-only login works while your first session stays open. Only then set PasswordAuthentication no and KbdInteractiveAuthentication no, run sshd -t to check the syntax, and reload rather than restart. Keeping the first session open is what makes a mistake recoverable.
Why does SSH still ask for a password after setting PasswordAuthentication no?
Almost always one of two reasons. Either KbdInteractiveAuthentication is still yes, so PAM offers a password prompt through a different mechanism, or a file in /etc/ssh/sshd_config.d/ is included after your change and overrides it. Run sudo sshd -T | grep -i passwordauth to see the value sshd actually resolved.
Should I use Ed25519 or RSA keys?
Ed25519 unless something in your environment cannot handle it. The keys are far shorter, verification is faster, and the security is at least equivalent to a 4096-bit RSA key. RSA remains a valid fallback for old appliances and legacy clients; if you use it, generate at least 4096 bits.
Does keys-only SSH stop brute-force attempts?
It stops them from ever succeeding, which is the point. It does not reduce their number: the bots have no way to know your configuration and keep connecting and offering passwords indefinitely. You still pay for each attempt in connections, forks and log lines, so blocking the sources is still worth doing.

Handle the traffic keys-only leaves behind

Subnet bans, whitelist first, the real SSH port detected for you. One server free forever, no card.