DevOps

How I Secured My Ubuntu VPS After Seeing Constant SSH Attack Attempts

A few weeks after deploying my personal blog to a VPS, I noticed something interesting in the system logs.

Every few minutes, new entries appeared:

Failed password for root
pam_unix(sshd:auth): authentication failure
Disconnected from authenticating user root

At first, I thought someone was specifically targeting my server.

The reality was less dramatic.

The internet is constantly scanning public IP addresses looking for weak SSH credentials.

If your VPS is exposed to the internet, these attacks will arrive automatically.

In this article, I'll share the exact steps I took to harden my Ubuntu VPS without making administration painful.

The First Surprise: Your Server Is Already Being Scanned

Running:

journalctl -f

showed repeated login attempts from different IP addresses.

Examples:

Failed password for root
authentication failure
invalid user admin
invalid user test

These are usually automated bots.

They continuously scan the internet and try common usernames such as:

root
admin
ubuntu
test
user

This is normal.

The important thing is ensuring those attempts never succeed.

Step 1: Create a Separate Administrative User

Using the root account for daily work is convenient.

It's also risky.

Instead, create a dedicated administrator account:

adduser nghia

Grant sudo access:

usermod -aG sudo nghia

Verify:

su - nghia
sudo whoami

Expected result:

root

At this point, nothing changes for your applications.

Nginx, PostgreSQL, Spring Boot, Docker, and systemd services continue running normally.

Only the login method changes.

Step 2: Switch to SSH Keys

Passwords can be guessed.

SSH keys are dramatically harder to attack.

Generate a new key pair on your personal device:

ssh-keygen -t ed25519 -C "vps-access"

When prompted for a file name, I recommend creating a dedicated key such as:

~/.ssh/id_ed25519_vps

I recommend creating a dedicated key specifically for the VPS.

Do not reuse:

  • GitHub keys
  • GitLab keys
  • Work laptop keys

Separate keys make revocation easier if one service is compromised.

Copy the public key to the server:

ssh-copy-id -i ~/.ssh/id_ed25519_vps.pub nghia@your-server-ip

Or manually add it to:

~/.ssh/authorized_keys

Verify that key-based login works:

ssh -i ~/.ssh/id_ed25519_vps nghia@your-server-ip

If you created a dedicated key, you may also want to add an SSH config entry:

Host app_name
    HostName your-server-ip
    User nghia
    IdentityFile ~/.ssh/id_ed25519_vps

Then connect using:

ssh app_name

Before changing any SSH settings:

Open a second terminal window and verify that key-based login works.

Never proceed until you've confirmed this.

Step 3: Disable Root Login

Once key authentication works, edit:

sudo nano /etc/ssh/sshd_config

Find:

PermitRootLogin yes

Change to:

PermitRootLogin no

Restart SSH:

sudo systemctl restart ssh

Now even if attackers know your root password, they cannot log in through SSH.

Step 4: Disable Password Authentication

This is one of the biggest security improvements.

In:

sudo nano /etc/ssh/sshd_config

Set:

PasswordAuthentication no
ChallengeResponseAuthentication no

Restart SSH:

sudo systemctl restart ssh

From this point forward:

Password login = impossible
SSH key = required

Most automated attacks become completely ineffective.

What If I Lose My Laptop?

This was my biggest concern.

The solution is simple:

Store encrypted backups of your private key.

For example:

  • Password manager
  • Encrypted USB drive
  • Secure cloud vault

Keep at least two backups.

Losing all copies of your SSH key is the real risk.

Not disabling password authentication.

Step 5: Change the SSH Port (Optional)

The default SSH port is:

22

Moving it won't stop attackers.

It only reduces noise.

Example:

Port 2222

After changing:

sudo systemctl restart ssh

Connect using:

ssh -p 2222 nghia@server-ip

Security through obscurity is not real security.

Treat this as a small bonus, not a primary defense.

Step 6: Install Fail2Ban

Fail2Ban automatically blocks IP addresses after repeated failed logins.

Install:

sudo apt update
sudo apt install fail2ban

Enable:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Check status:

sudo fail2ban-client status sshd

Now attackers receive temporary bans after multiple failures.

Step 7: Keep the Firewall Simple

Ubuntu includes UFW.

Allow only required services:

sudo ufw allow 80
sudo ufw allow 443
sudo ufw allow 22

Enable:

sudo ufw enable

Verify:

sudo ufw status

If you changed the SSH port, allow that port instead.

Everything else should remain closed.

Step 8: Enable Automatic Security Updates

Install:

sudo apt install unattended-upgrades

Enable:

sudo dpkg-reconfigure unattended-upgrades

This automatically installs important security patches.

For a small personal VPS, this is usually worth it.

Step 9: Monitor Logs Regularly

The easiest security tool is still your logs.

Useful commands:

journalctl -u ssh
journalctl -f
last
lastb

If something unusual happens, the logs usually tell the story first.

My Current VPS Security Baseline

Today my minimum VPS security checklist looks like this:

  • Dedicated sudo user
  • SSH keys only
  • Root login disabled
  • Password login disabled
  • Fail2Ban enabled
  • Firewall enabled
  • Automatic security updates enabled
  • Regular log monitoring

None of these steps are complicated.

Together, they dramatically reduce the attack surface of a small Ubuntu server.

Most importantly, they protect against the kind of automated attacks that every internet-facing VPS experiences from day one.