If you've ever run tail -f /var/log/auth.log on a fresh VPS, you already know the problem: within minutes, bots from all over the world are hammering port 22 trying root/admin/password123. Most of these attempts go nowhere, but "most" isn't good enough when it's your server. This guide walks through the four changes that actually move the needle — SSH keys, no root login, a non-default port, and Fail2Ban — in the order you should make them so you never lock yourself out.

Symptom: Constant Login Attempts, Or Worse, a Compromised Account

Two situations bring people to this guide. The mild one: you check /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (CentOS/AlmaLinux) and see thousands of failed sshd login attempts a day. The severe one: you notice unfamiliar cron jobs, a spike in outbound traffic, or a new user account you didn't create — signs someone actually got in, usually through a weak or reused password on the root account.

Either way, the fix is the same set of steps. Do them in order.

Cause: Password Auth + Root Login Is an Open Door

By default, most fresh VPS images ship with:

  • Password authentication enabled — meaning brute-force is possible at all
  • root allowed to log in directly over SSH — meaning attackers only need to guess one username
  • SSH listening on port 22 — the first port every scanner checks
  • No automated banning of repeat offenders

None of these alone is fatal, but stacked together they turn your server into a low-effort target. Fixing all four takes about fifteen minutes.

Fix: Step 1 — Set Up Key-Based Authentication First

Do this before touching anything else. If you disable password login without a working key, you'll lock yourself out.

On your local machine (not the server):

ssh-keygen -t ed25519 -C "your-name@yourdomain.com"

Press enter to accept the default file location, and set a passphrase if you want an extra layer (recommended, especially on laptops). Then copy the public key to your server:

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server-ip

If ssh-copy-id isn't available (common on Windows), paste the contents of id_ed25519.pub manually into ~/.ssh/authorized_keys on the server:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys   # paste the public key, save
chmod 600 ~/.ssh/authorized_keys

Test it in a new terminal window before closing your current session. Run ssh user@your-server-ip and confirm you get in without a password prompt (or only a passphrase prompt for your key). If it fails, fix it now — don't move to step 2 with only one working session.

Step 2 — Create a Non-Root Sudo User (If You're Still on Root)

A lot of VPS providers hand you a fresh box with only a root account. Create a normal user with sudo rights before locking root out:

adduser deployuser
usermod -aG sudo deployuser        # Debian/Ubuntu
usermod -aG wheel deployuser       # CentOS/AlmaLinux/RHEL

Copy your key over to this user too — either repeat ssh-copy-id targeting deployuser@your-server-ip, or copy root's authorized_keys into the new user's ~/.ssh/ and fix ownership:

mkdir -p /home/deployuser/.ssh
cp /root/.ssh/authorized_keys /home/deployuser/.ssh/
chown -R deployuser:deployuser /home/deployuser/.ssh
chmod 700 /home/deployuser/.ssh
chmod 600 /home/deployuser/.ssh/authorized_keys

Log in as deployuser in a fresh terminal and confirm sudo whoami returns root before continuing.

Step 3 — Edit sshd_config

Open the SSH daemon config:

sudo nano /etc/ssh/sshd_config

Find and set these values (uncomment if needed):

PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
Port 2222

A few notes on that last one — changing the port from 22 to something else (pick anything above 1024 and below 65535, avoiding common alternates like 2222 if you want to dodge even the lazier scanners) won't stop a determined attacker, but it silences the constant background noise from automated scanners, which makes your real auth logs much easier to read.

Save the file, then test the config for syntax errors before restarting anything:

sudo sshd -t

No output means the config is valid. If you changed the port, open it in your firewall before restarting SSH:

sudo ufw allow 2222/tcp
sudo ufw reload

Now restart SSH:

sudo systemctl restart sshd

Do not close your current session yet. Open a brand-new terminal and connect using the new port and your key:

ssh -p 2222 deployuser@your-server-ip

Only close the original session once this new connection works. This is the single most important habit in server hardening — always keep one working session open until you've verified the change from a fresh connection.

Step 4 — Install and Configure Fail2Ban

Fail2Ban watches your logs and temporarily bans IPs that fail login too many times. Install it:

sudo apt update && sudo apt install fail2ban -y      # Debian/Ubuntu
sudo dnf install fail2ban -y                          # CentOS/AlmaLinux

Never edit jail.conf directly — it gets overwritten on updates. Create a local override instead:

sudo nano /etc/fail2ban/jail.local

Add:

[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 4
bantime = 3600
findtime = 600

On CentOS/AlmaLinux, set logpath = /var/log/secure instead. Save, then start and enable the service:

sudo systemctl enable fail2ban
sudo systemctl restart fail2ban

Check that the sshd jail picked up your settings:

sudo fail2ban-client status sshd

You'll see a count of currently banned IPs, which stays at zero until someone trips the limit — that's normal on a fresh install.

Prevention: Keep It That Way

HabitWhy it matters
Never share private keys over chat/emailA leaked key is as bad as a leaked password
Rotate keys when someone leaves the teamRemoving a line from authorized_keys takes seconds
Check fail2ban-client status sshd monthlyConfirms the jail is actually catching attempts
Keep one root-equivalent recovery path (console access via your host's control panel)Backup access if you ever lock yourself out over SSH
Apply the same key-only rule to any new user you createOne password-auth account undoes all of this

If you're on a SkyServer VPS, you can always reach your server through the browser-based console in your control panel even if SSH itself becomes unreachable — worth confirming that access works before you need it, not during an incident.

Frequently Asked Questions

What if I lock myself out after changing sshd_config?

Use your hosting provider's browser-based console (VNC/serial console) to log in locally without SSH, then revert the change in /etc/ssh/sshd_config and restart sshd. This is exactly why you should never close your original session until a new connection is confirmed working.

Is changing the SSH port actually useful, or just security through obscurity?

It's not a real security boundary on its own, but it dramatically cuts the noise from automated scanners that only check port 22, making your logs easier to monitor and slightly reducing your exposed attack surface. Pair it with key-only auth and Fail2Ban — don't rely on it alone.

Can I use password authentication for one specific account and keys for others?

Yes, using a Match User block in sshd_config, but this reintroduces brute-force risk for that account. It's better to issue that person a key too — key generation takes under a minute.

Will Fail2Ban ban my own IP if I mistype my password a few times?

Yes, if you exceed maxretry within findtime. Add your own static IP to the ignoreip line in jail.local (e.g. ignoreip = 127.0.0.1/8 203.0.113.5) to avoid banning yourself.

Do I still need a firewall like UFW if I'm using Fail2Ban?

Yes — they solve different problems. UFW controls which ports are reachable at all; Fail2Ban reacts to repeated failed attempts on ports that are open. Run both together for layered protection.