Put any server on the internet with SSH open on port 22, and within minutes bots start guessing passwords. They aren't targeting you — they scan every address, all day, trying root, admin, ubuntu and thousands of common passwords. This guide shows how to check whether it's happening to you, and the five changes that make it harmless. Every step works on Ubuntu 22.04 and 24.04.
Before you start: keep your current SSH session open the whole time, and test each change from a second terminal. If something goes wrong, the open session lets you undo it. Your cloud provider's web console is the backup way in.
1. Check whether you're being attacked
Count the failed password attempts in the auth log:
sudo grep -c "Failed password" /var/log/auth.log
And see which IP addresses are trying hardest:
sudo grep "Failed password" /var/log/auth.log \ | grep -oE 'from [0-9a-f.:]+' | sort | uniq -c | sort -rn | head
On a server that has been online for a day, hundreds or thousands of failures are normal. Our guide to seeing who is trying to log in goes deeper.
2. Log in with an SSH key instead of a password
A brute-force attack is password guessing. An SSH key can't be guessed, so switching to keys is the single biggest fix. On your own computer (not the server), create a key if you don't have one:
ssh-keygen -t ed25519 -C "you@laptop"
Copy it to the server, then check you can log in without a password:
ssh-copy-id -i ~/.ssh/id_ed25519.pub youruser@your-server ssh youruser@your-server
Do this for every person and machine that needs access before moving on — the next step turns passwords off.
3. Turn off password logins (the right way on Ubuntu)
Ubuntu reads SSH settings from /etc/ssh/sshd_config and every file in /etc/ssh/sshd_config.d/. Two details catch people out:
- The first value wins. Files in
sshd_config.dare read in name order, and sshd keeps the first value it sees for each setting. - Cloud images often ship
50-cloud-init.confwithPasswordAuthentication yes. A file named99-…would be ignored.
So put your settings in a file whose name sorts first, 00-hardening.conf:
sudo tee /etc/ssh/sshd_config.d/00-hardening.conf >/dev/null <<'EOF' PasswordAuthentication no KbdInteractiveAuthentication no PermitRootLogin no MaxAuthTries 3 LoginGraceTime 20 EOF
PermitRootLogin no stops direct root logins (use sudo from your own user instead); MaxAuthTries and LoginGraceTime make each connection give up sooner. Check the syntax, then confirm what sshd will actually use:
sudo sshd -t sudo sshd -T | grep -Ei '^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin|maxauthtries)'
You should see passwordauthentication no. If it still says yes, another file is setting it first — grep -ri passwordauthentication /etc/ssh/ finds it. Then apply the change:
sudo systemctl restart ssh
Restarting doesn't drop sessions that are already open. Now, from a second terminal, check that your key still works — and that a password is refused:
ssh youruser@your-server ssh -o PubkeyAuthentication=no youruser@your-server # should fail: "Permission denied (publickey)"
4. Rate-limit new SSH connections
Ubuntu's firewall, ufw, can refuse an IP that opens too many SSH connections too fast (six within 30 seconds). Add the rule before enabling the firewall, or you'll lock yourself out:
sudo ufw limit OpenSSH sudo ufw enable sudo ufw status
If you serve websites from the same server, also run sudo ufw allow 80,443/tcp. Many cloud providers have a network firewall too — you can restrict port 22 there to your own IPs if they rarely change.
5. Block attackers who keep trying
With passwords off, guessing can no longer succeed — but bots keep connecting, filling your logs and using resources. Blocking an IP after repeated failures stops that.
ThreatGuard installs with one command, shows every attempt on every server live — which IPs, which countries, which usernames — and blocks attackers at the firewall when they cross your rule. IPs that logged in successfully recently are never auto-blocked, so you don't ban yourself. To block a single IP by hand, see how to block an IP address on Linux.
What about changing the SSH port?
Moving SSH off port 22 cuts the noise from simple bots, but it isn't protection — scanners find SSH on any port. If you do it on Ubuntu 22.10 or later, SSH is started by ssh.socket, so the port must change there too (or the socket disabled), not just in sshd_config. Keys and no passwords matter far more.
Checklist
- Every user logs in with an SSH key.
sshd -Tshowspasswordauthentication noandpermitrootlogin no.ufw statusshowsLIMITfor OpenSSH.- Repeat attackers are blocked automatically.
- You can see the attacks, so you notice if something changes.