The only three that carry the weight
Almost all of your real protection comes from three settings. Get these right and the wall of bot traffic in your logs becomes completely harmless noise.
First, use keys instead of passwords, and then forbid passwords entirely. A password can be guessed. A properly generated SSH key cannot be, not in the lifetime of the universe. Once you've confirmed your key works, this line is what closes the door:
PasswordAuthentication noWith that set, every one of those thousands of bots is trying a door that has no keyhole. They can guess forever and never get in. This single line does more than everything else on this page combined.
Second, stop root from logging in directly:
PermitRootLogin noYou log in as a normal user and escalate with sudo. Why it helps: root is the one username every attacker already knows exists on every Linux box. Forcing them to guess both a valid username and a key they can't produce removes the free half of the problem. It also means every privileged action goes through sudo, which logs who did what.
Third — and this isn't an sshd setting — keep the machine patched. The scary SSH vulnerabilities of the last few years were fixed by an apt upgrade, not by any config tweak. Unattended security updates are worth more than any single line below:
apt install unattended-upgrades
dpkg-reconfigure -plow unattended-upgradesThat's the core. Everything after this is refinement or theater.
Do the key part right
Weak keys undercut everything, so generate a good one on your own machine, not the server:
ssh-keygen -t ed25519 -a 100 -C "you@laptop"Ed25519 is the modern default: short, fast, and strong. Skip RSA unless something ancient forces it, and if it does, never go below 4096 bits. Copy the public half up:
ssh-copy-id you@your-server-ipThen log in with the key in a second terminal and confirm it works before you disable passwords. Do not skip that confirmation. Locking out password auth while your key is broken is the single most common way people fatfinger themselves out of their own server. Keep the first session open until the second one succeeds.
The full sshd_config that matters
Put together, the settings worth setting live in /etc/ssh/sshd_config (or a drop-in file under /etc/ssh/sshd_config.d/):
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication noThat fourth line closes a side door: some distros ship keyboard-interactive auth enabled, which can be another password-ish path. Turn it off so PasswordAuthentication no isn't quietly bypassed. Apply changes with:
sshd -t && systemctl reload sshThe sshd -t tests the config first. Run it every time. A typo in this file plus a reload can refuse all future logins, and sshd -t catches the typo before it bites.
Now the cargo cult
Here's where I'll annoy people. These are the steps that feel like security and mostly aren't.
Moving SSH off port 22. This is the most popular "hardening" tip and it protects you from essentially nothing. An attacker who can't guess your key doesn't care what port it's on, and a real targeted scan finds your SSH on port 2222 in seconds. What changing the port actually does is quiet your logs, because the dumb broad-sweep bots only hit 22. That's a legitimate reason to do it — less noise makes real events easier to spot — but call it what it is: noise reduction, not risk reduction. Don't let it stand in for PasswordAuthentication no.
Port knocking. You configure the firewall to open SSH only after a secret sequence of connection attempts to closed ports. It's clever, it's fun to set up, and it adds fiddly failure modes for a threat model you already closed with key-only auth. If a bot can't authenticate anyway, hiding the port from it buys you very little for real complexity. Skip it unless you enjoy it as a hobby.
Fail2ban as your main defense. Fail2ban watches your logs and bans IPs that fail too many times. It's fine, and it does trim log noise and stop the dumbest floods. But notice: with password auth already disabled, those failing IPs were never going to get in. Fail2ban is banning people from a locked door. It's a reasonable nice-to-have for tidiness and to blunt resource use from aggressive scanners — it is not the thing keeping you safe, and treating it as your primary control means you've mistaken the janitor for the lock.
The pattern across all three: they operate on attackers who already can't succeed. Real security came from removing the thing they were attacking (the password). These add friction, mostly to your logs, sometimes to yourself.
What's actually worth adding on top
If you've done the core and want to go further, these earn their keep:
- A firewall that default-denies inbound and only opens what you use.
ufw default deny incoming, then allow SSH and your actual services. This limits blast radius if some other service is the weak point. - Better still, don't expose SSH to the internet at all. Put it behind a WireGuard VPN and bind sshd to the VPN interface, so the public internet can't even reach the SSH port. This is a genuine step up from every myth above, because it removes SSH from the attack surface entirely instead of just filtering who reaches it.
AllowUsers youto whitelist exactly which accounts can log in, so a stray service account can never be an SSH entry point.
Notice these change what's reachable and what's exposed. That's the difference between hardening and theater: real hardening shrinks the attack surface, theater decorates it.