Step-by-step tutorial, 2026
SSH hardening, done in the right order. Tested on our own server.
We hardened our own server with exactly these steps. In the 24 hours before, it logged 821 failed password guesses. In the hours after: none.
24 hours before
00-hardening.conf
PermitRootLogin no PasswordAuthentication no KbdInteractiveAuthentication no AllowUsers deploy
After
0 password guesses
Bots still connect. Nothing left to guess.
The short answer
Put four lines in a file called /etc/ssh/sshd_config.d/00-hardening.conf: PermitRootLogin no, PasswordAuthentication no, KbdInteractiveAuthentication no and AllowUsers you. Check it with sudo sshd -t, reload with sudo systemctl reload ssh, and test a new login before you close your session.
The 00- name matters: SSH uses the first value it reads, and other files can quietly override your edits. Confirm the result with sudo sshd -T, or paste it into our free checker.
Our own server was taking a password guess every couple of minutes. In one day: 821 failed passwords, 539 of them for root.
So we did what this tutorial describes. In the first hours after, not one password was tried, because the server no longer accepts passwords at all. Bots connect, see that only keys work, and leave.
Here’s the trap we nearly fell into. The server’s image shipped two extra SSH config files that switch passwords and root login on. Edit the main file, and nothing changes. Most tutorials never mention this, and most skip the way newer Ubuntu starts SSH, which is why so many port changes on 24.04 seem to do nothing.
This guide walks through it in the order that can’t lock you out, with the checks we used ourselves.
In this guide you’ll learn
- The four settings that matter, and the one-file way to set them
- A free checker: paste
sshd -T, see what your server really allows - Why your edit may do nothing, and how drop-in files win
- A safety net that undoes a bad change by itself
- Changing the SSH port on Ubuntu 22.04 and 24.04, socket activation included
- fail2ban and ufw limit, and what they add
Chapter 1
The short answer
These four settings do most of the work. Each is a keyword in sshd_config.
| Setting | Set to | What it stops |
|---|---|---|
| PasswordAuthentication | no | All password guessing |
| KbdInteractiveAuthentication | no | Password prompts by another route |
| PermitRootLogin | no | Logins as root, the most guessed account |
| AllowUsers | your user | Logins as any other account |
Before you start: log in with an SSH key as your own user with sudo. If you haven’t yet, follow our SSH keys tutorial and the user steps in the VPS security guide.
Starting fresh? Deploy a Lite 2 with your public key added at deploy, and you can apply all four settings in its first five minutes. It bills by the hour, and the web console is there if a setting goes wrong.
Chapter 2
Check what your server really allows
sudo sshd -T prints the settings SSH actually uses, after reading every config file. Paste it below. The checker flags what’s open and writes the fix.
Paste your sshd -T output on the left.
Click “Load our server’s old settings” to see what our server looked like before: two red flags, both from the image’s own files.
Chapter 3
What changed on our server
We counted login attempts in our server’s SSH log for the day before the change and the first hours after.
| 24 hours before | First 1 h 49 min after | |
|---|---|---|
| Failed password guesses | 821 | 0 |
| of which for root | 539 | 0 |
| Logins for users that don’t exist | 183 | 15 |
| Refused by AllowUsers | not set | 81 |
The bots didn’t stop knocking. What changed is that they can’t try a password any more: the server offers only key login, and every account except ours is refused before it gets that far. fail2ban, which bans repeat offenders, had banned 193 addresses since the server last started.
Chapter 4
Why your edit may do nothing
Modern Ubuntu reads extra files from /etc/ssh/sshd_config.d/, and two rules decide who wins.
- The first value wins. For each keyword, SSH uses the first value it reads and ignores the rest.
- Drop-ins come first. Settings in
sshd_config.doverride those in the main configuration file. Files there are read in name order.
Our server’s image came with two drop-ins of its own, a 00- and a 99- file, both with PasswordAuthentication yes. Cloud images often add a file through cloud-init too, which controls password login with its ssh_pwauth setting. Any of these beats a change at the bottom of sshd_config.
$ sudo sshd -T | grep -Ei "^(permitrootlogin|passwordauthentication|allowusers) "permitrootlogin nopasswordauthentication noallowusers deploy
Chapter 5
Lock it down without locking yourself out
Do this from a session that’s already logged in with your key. Don’t close it until the last step.
Arm a safety net
This undoes the change by itself in 3 minutes unless you cancel it:
sudo systemd-run --on-active=180 --unit=ssh-rollback \ sh -c 'rm -f /etc/ssh/sshd_config.d/00-hardening.conf; systemctl reload ssh'
Write the drop-in
sudo tee /etc/ssh/sshd_config.d/00-hardening.conf > /dev/null <<'EOF' PermitRootLogin no PasswordAuthentication no KbdInteractiveAuthentication no AllowUsers maria EOF
Test the config, then reload
sudo sshd -t && sudo systemctl reload ssh
sshd -tprints nothing when the config is valid. A reload keeps your current session.Open a new session
From your PC, in a new window, log in with your key. If it fails, wait: the safety net puts things back.
Verify, then cancel the safety net
sudo sshd -T | grep -Ei "^(permitrootlogin|passwordauthentication|allowusers) " sudo systemctl stop ssh-rollback.timer
Chapter 6
Root login: no, or prohibit-password?
PermitRootLogin takes four values: yes, prohibit-password, forced-commands-only or no.
- OpenSSH’s own default is prohibit-password: root can log in with a key, never a password. Some server images change it to
yes, as the one we tested did. - no is safer still: log in as yourself and use
sudo. Every root guess then fails before it starts.
MythRoot login is open by default in SSH.
Not in OpenSSH: the default is prohibit-password. It’s some server images and old configs that open it.
MythAllowUsers is enough on its own.
It limits who can try. Passwords off is what makes guessing pointless. Use both.
Chapter 7
Changing the SSH port
Moving SSH off port 22 cuts the noise in your logs. It isn’t security on its own: anyone who scans properly still finds the new port. Keys are what keep attackers out.
If you still want to, the order matters, and Ubuntu changed how it works in 22.10.
Open the new port first
sudo ufw allow 2222/tcp
Set the port
echo 'Port 2222' | sudo tee /etc/ssh/sshd_config.d/00-port.conf sudo sshd -t
Ubuntu 22.04: restart the service
sudo systemctl restart ssh
Ubuntu 22.10 and later (24.04): restart the socket
Since 22.10, SSH starts from a systemd socket. After changing Port, run daemon-reload, then restart ssh.socket:
sudo systemctl daemon-reload sudo systemctl restart ssh.socket
Test, then close port 22
In a new window:
ssh -p 2222 you@server. Only when that works:sudo ufw delete allow 22/tcp
Chapter 8
fail2ban and ufw limit
With passwords off, guessing can’t succeed. These two tools cut the noise and the load.
- ufw limitHow to check:
sudo ufw limit 22/tcpdenies an address that makes 6 or more connections within 30 seconds. - fail2ban sshd jailHow to check: fail2ban reads the log and bans repeat offenders for a while. Its jails are off until you enable them; the sshd jail is the one you want.
- Watch the effectHow to check:
sudo fail2ban-client status sshdshows current and total bans. Ours had banned 193 addresses. - Moved the port?How to check: Tell the jail: set
port = 2222under[sshd]in/etc/fail2ban/jail.local, or bans block port 22 only.
Chapter 9
If you do lock yourself out
With the safety net, a mistake fixes itself in three minutes. Without it, you need a way in that doesn’t use SSH.
- Open your server’s web console. Every LiteKeep server has one on its page in your account. Log in there and delete or fix
00-hardening.conf, thensudo systemctl reload ssh. - Read the log to see why:
sudo journalctl -u ssh -n 50. Our Permission denied guide decodes every line.
Now it’s your move
SSH hardening is four lines in the right file, done in the right order. The bots will keep knocking; they just won’t have anything to guess.
New server? A Lite bills by the hour, so practising this costs cents. Deploy a Lite 2, lock it down in ten minutes, and keep the web console as your safety net.