How to protect a VPS from SSH brute force attacks
Protect a VPS from SSH brute force on Ubuntu or Debian: key-only login, Fail2ban, UFW rate limits, changing the port safely, and how not to lock yourself out.

Key takeaways
- Turning off SSH password login and using keys only is the single most effective defence against brute force.
- Fail2ban bans IPs after a few failed logins, cutting log noise and load.
- Changing the SSH port only reduces bot noise; on Ubuntu 24.04 it also needs a restart of ssh.socket.
- Always keep your current SSH session open and test a new login before closing it.
The most effective way to protect a VPS from SSH brute force is to turn off password login entirely and allow SSH keys only: then bots can try millions of passwords and none will work. On top of that, add Fail2ban to ban IPs that keep failing, rate-limit connections in the firewall, and where possible allow SSH only from your own IPs. Changing the SSH port makes logs quieter, but it isn't a primary defence.
This guide walks through each step on Ubuntu 24.04 and Debian 12/13, in an order that won't lock you out of your own server, and shows what ZoPanel sets up and checks for you.
Is your VPS being brute-forced right now?
Almost certainly. Every public IP gets constant scans on port 22, often within minutes of the VPS being created. Take a look:
# Ubuntu and Debian both use the ssh.service unit
sudo journalctl -u ssh --since "24 hours ago" | grep -cE "Failed password|Invalid user"
Thousands a day is normal. Most of it is bots trying common usernames such as root, admin, ubuntu and test with weak passwords. They aren't targeting you specifically, but one weak password is enough to turn the server into a crypto miner or a spam relay.
Step 1: log in with an SSH key
On your own computer (Linux, macOS or Windows with OpenSSH):
ssh-keygen -t ed25519 -C "you@laptop"
ssh-copy-id root@203.0.113.10
Ed25519 keys are short, fast and the recommended choice for new keys. Give the private key a passphrase, so a lost laptop doesn't mean an instantly usable key.
If you have a hardware security key (a YubiKey or similar), you can create an ed25519-sk key, which requires a touch on the device for every login:
ssh-keygen -t ed25519-sk
Log in again with the key before moving to step 2. If the key doesn't work, stop and fix it: the next step turns passwords off.
It's also a good idea to work as a regular sudo user rather than as root:
adduser admin2
usermod -aG sudo admin2
mkdir -p /home/admin2/.ssh
cp /root/.ssh/authorized_keys /home/admin2/.ssh/
chown -R admin2:admin2 /home/admin2/.ssh
chmod 700 /home/admin2/.ssh && chmod 600 /home/admin2/.ssh/authorized_keys
Step 2: turn off password login
On Ubuntu 24.04 and Debian 12/13, /etc/ssh/sshd_config includes the files in /etc/ssh/sshd_config.d/ right at the top. For sshd, the first value read wins. Some cloud images ship a 50-cloud-init.conf that sets PasswordAuthentication yes, so give your file a name that sorts first:
sudo nano /etc/ssh/sshd_config.d/00-hardening.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
MaxAuthTries 3
LoginGraceTime 30
PermitRootLogin prohibit-passwordlets root log in with a key but never with a password. If you created a sudo user in step 1,PermitRootLogin nois stricter still.MaxAuthTries 3drops the connection after three failed authentication attempts.LoginGraceTime 30gives each connection 30 seconds to log in.
Validate before reloading:
sudo sshd -t # no output means the syntax is fine
sudo sshd -T | grep -E "passwordauthentication|permitrootlogin|maxauthtries"
sudo systemctl reload ssh
Keep your current SSH session open. Open a new terminal window and log in. Only close the old session once the new one works. If your provider has a web console (VNC), find out where it is before you start.
Step 3: install Fail2ban
With passwords off, brute force can't succeed, but bots still tie up connections and fill your logs. Fail2ban reads the logs and, when an IP fails too many times, bans it in the firewall for a while.
sudo apt install fail2ban
Don't edit jail.conf (it belongs to the package and can be overwritten on upgrade). Create /etc/fail2ban/jail.local:
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
bantime.increment = true
[sshd]
enabled = true
backend = systemd
backend = systemd matters on Debian 12 and later: Debian no longer writes /var/log/auth.log by default, and the sshd jail won't start if it goes looking for that file. bantime.increment makes bans longer for repeat offenders.
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd # currently banned IPs
sudo fail2ban-client set sshd unbanip 198.51.100.7 # unban if you banned yourself
If you work from a fixed IP, add ignoreip = 127.0.0.1/8 ::1 YOUR_IP under [DEFAULT] so a typo never bans you.
Since version 9.8, OpenSSH has PerSourcePenalties, on by default, which penalises addresses that repeatedly fail authentication (see the OpenSSH 9.8 release notes). Debian 13 ships OpenSSH 10.0, so it has this; Ubuntu 24.04 (OpenSSH 9.6) and Debian 12 (9.2) don't, so Fail2ban still earns its place there.
Step 4: rate-limit SSH in the firewall
UFW has a built-in limit rule: it denies an IP that opens 6 or more connections within 30 seconds.
sudo ufw limit 22/tcp
sudo ufw status
Stronger still is allowing only your own IPs on the SSH port, either in your provider's cloud firewall (security group) or in UFW:
sudo ufw allow from 198.51.100.7 to any port 22 proto tcp
sudo ufw delete limit 22/tcp
That removes almost all bot traffic, but it only suits a fixed IP or a VPN such as WireGuard. If your home IP changes, you'll need the provider's console to get back in.
Step 5: should you change the SSH port?
Moving SSH off port 22 cuts automated scanning sharply and makes logs easier to read. It does not stop a determined attacker, since scanning every port takes minutes. Treat it as noise reduction, done after keys and Fail2ban.
The safe order:
- Open the new port in the firewall first:
sudo ufw allow 2222/tcp(and in the cloud firewall, if you use one). - Add
Port 2222to00-hardening.conf. - Apply it:
- Ubuntu 24.04: SSH is socket-activated, so the listening port comes from
ssh.socket. Runsudo systemctl daemon-reload && sudo systemctl restart ssh.socket. Restartingssh.servicealone isn't enough. - Debian 12/13:
sudo systemctl restart ssh.
- Ubuntu 24.04: SSH is socket-activated, so the listening port comes from
- Check with
sudo ss -tlnp | grep ssh, and log in from a new session withssh -p 2222. - Once you're sure, remove the port 22 firewall rule. The
sshdjail bans on thesshport (22) by default, so addport = 2222to its[sshd]section.
Step 6: keep OpenSSH updated
Brute force isn't the only threat. In 2024 the regreSSHion flaw (CVE-2024-6387) in sshd affected portable OpenSSH 8.5p1 through 9.7p1 and could lead to remote code execution as root. Ubuntu and Debian patched it in their own packages, so the version number you see may still look old: check that package updates are applied rather than reading the version string.
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
The rest of VPS hardening (users, automatic updates, exposed services) is covered in how to secure an Ubuntu VPS.
How people lock themselves out
| Mistake | How to avoid it |
|---|---|
| Passwords turned off before the key works | Test key login first and keep the old session open |
| A cloud-init file turns passwords back on | Name your file 00-...conf and check with sshd -T |
| New port not open in the firewall | Open the new port first, close the old one last |
| Ubuntu 24.04 still listening on 22 | Restart ssh.socket after daemon-reload |
| Fail2ban bans your own IP | Add ignoreip and know the unbanip command |
| SSH allowed from one IP, then the IP changes | Use a VPN, or know how to reach your provider's console |
Protecting a VPS from SSH brute force with ZoPanel
When you install ZoPanel, the installer does part of this for you, as described in the Security documentation:
- UFW is turned on with your current SSH port plus 80, 443 and 8888 open, and enabled at boot. Manage rules under Security → Firewall.
- Fail2ban gets an
sshdjail (5 failures in 10 minutes, 1 hour ban) and azopaneljail for panel password and 2FA failures (8 failures in 15 minutes, 1 hour ban). Banned IPs appear on the Security page, where you can unban them with one click. - Security Center scores the server, including SSH root password login, SSH password authentication, SSH login attempts and Fail2ban. The Fix buttons for SSH always check that a key is set up first, so a fix can't lock you out.
Hosting customers never get a root shell in ZoPanel. Their SFTP access is chrooted to their home directory, they can add SSH keys under My account → SFTP & SSH keys and turn on Keys only to disable password login for their account (see FTP and SFTP). Why the panel itself never runs as root, or offers a root shell over the web, is explained in why a hosting panel should never run as root.
The takeaway
The right order is keys first, then passwords off, then Fail2ban, then rate limits or an IP allowlist, and only then a port change if you want quieter logs. Do every step with an SSH session still open. After that, keeping OpenSSH patched matters just as much.
ZoPanel sets up UFW, Fail2ban and the SSH checks at install time, on the Free plan too. Install it with curl -fsSL https://get.zopanel.net | sudo bash on Ubuntu 22.04/24.04 or Debian 12/13, and see pricing when you need more sites.
Frequently asked questions
Do I still need Fail2ban if SSH passwords are disabled?
It's still worth having. With keys only, password brute force can't succeed, but bots keep opening thousands of connections, wasting resources and cluttering logs. Fail2ban bans them early, and it protects other services such as mail or FTP if you enable jails for them.
Does changing the SSH port stop brute force attacks?
It reduces automated scanning and makes logs quieter, but it won't stop anyone who scans every port. Use it as an extra layer after SSH keys and Fail2ban, not as a replacement.
What if Fail2ban bans my own IP?
Connect from another IP or through your VPS provider's web console, then run sudo fail2ban-client set sshd unbanip YOUR_IP. In ZoPanel you can also unban it on the Security page if you can still reach the panel from another address.
Which SSH key type should I use?
Ed25519 is a good choice for new keys: short, fast and secure. With a hardware security key, ed25519-sk requires a touch on every login. RSA is still fine for older systems that need it, at 3072 bits or more.
Why is Ubuntu 24.04 still listening on port 22 after I changed it?
Ubuntu 24.04 uses socket activation for SSH, so the port is set by ssh.socket. After changing Port, run sudo systemctl daemon-reload and then sudo systemctl restart ssh.socket, and confirm with ss -tlnp.
Install ZoPanel free
One command on a fresh Ubuntu or Debian server. Up and running in minutes.
Install in 5 minutesKeep reading

How to secure an Ubuntu VPS: 10 steps for the first hour
Secure an Ubuntu VPS (24.04) step by step: SSH keys, no password logins, UFW, Fail2ban, automatic updates and backups, with exact commands and traps to avoid.

Best VPS specs for WordPress: how much CPU, RAM and disk you need
The best VPS specs for WordPress for 1, 10 or 100 sites: how to size CPU, RAM and disk from your traffic, with real measurements and the mistakes to avoid.

Cloudflare with VPS hosting: SSL, DNS and real visitor IPs done right
How to use Cloudflare with VPS hosting: Full (strict) SSL, which records to proxy, real visitor IPs, and how to avoid redirect loops and origin IP leaks.