Back to blog
Security14 August 20269 min readVMFrost Team

Hardening your first VPS: the 30-minute checklist

A fresh VPS is exposed to the public internet the moment it boots, and automated scanners will find it within minutes. Here is the short list of changes that removes the overwhelming majority of that risk.

Put a server on a public IP and it will start receiving unsolicited SSH login attempts almost immediately. None of it means anyone is targeting you specifically. It is background noise from automated scanners sweeping the entire IPv4 space, continuously. The good news is that this noise is defeated almost entirely by a handful of standard changes.

Work through this in order. It takes about half an hour on a fresh Debian or Ubuntu install.

1. Update everything before you do anything else

Your image was built at some point in the past. Patch it before you expose any services.

sudo apt update && sudo apt upgrade -y
sudo reboot

2. Create a non-root user

Working as root full-time means every typo is potentially unrecoverable and every compromised process is a full compromise. Create a user with sudo rights and use that instead.

adduser deploy
usermod -aG sudo deploy

3. Switch to SSH keys and disable password login

This is the single highest-value change on the list. A password can be guessed; a 4096-bit key can’t be, in any practical sense. Generate the key on your local machine, not on the server:

# On your laptop, not the server
ssh-keygen -t ed25519 -C "vmfrost-vps"
ssh-copy-id [email protected]

Confirm you can log in with the key in a second terminal before you lock the door behind you. Then edit /etc/ssh/sshd_config:

PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes
sudo systemctl restart ssh

Keep your existing SSH session open until you have verified the new one works. If you lock yourself out, console access is the only way back in.

4. Turn on a firewall with a default-deny policy

Default-deny means anything you haven’t explicitly allowed is blocked. This protects you from services you forgot were listening.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

5. Install fail2ban

With password auth disabled the brute-force attempts can’t succeed, but they still consume resources and clutter your logs. fail2ban bans repeat offenders at the firewall level.

sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

6. Enable unattended security upgrades

Most real-world compromises exploit a known vulnerability that had a patch available. Automating security patches closes that window without requiring you to remember.

sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades

7. Audit what is actually listening

You may be surprised. Databases in particular have a habit of binding to 0.0.0.0 by default.

sudo ss -tulpn

Anything that only needs to be reachable by other processes on the same box should bind to 127.0.0.1 instead. A firewall is a second line of defence, not a substitute for correct bind addresses.

What this doesn’t cover

This checklist secures the server. It doesn’t secure what you run on it. An outdated CMS, a leaked API key in a public repository, or a web application with an injection flaw will all get you compromised through a port you deliberately left open. Treat application security as a separate and ongoing job.

  • Keep application dependencies patched, not just OS packages.
  • Never commit secrets to version control; use environment variables or a secrets manager.
  • Put TLS in front of anything serving traffic. Certificates are free via Let’s Encrypt.
  • Take backups and test restoring them, because hardening reduces risk rather than eliminating it.

Ready to spin one up?

No email required. Generate a token and you're running.