Every fresh VPS arrives with default settings that are convenient for setup and terrible for production. Thirty minutes of hardening eliminates most trivial attack vectors and sets up the patterns you'll rely on for years. This is the playbook.

The goal of this 30-minute window

  1. Remove default login weaknesses (password SSH, root login).
  2. Limit exposed surface (firewall).
  3. Harden against brute force (fail2ban, non-standard SSH port optionally).
  4. Enable automated security updates.
  5. Set up basic monitoring so you see patterns.

Before you start

Have ready:

  • Your SSH public key (id_ed25519.pub or id_rsa.pub).
  • The root password emailed by your provider (you'll log in once as root to set up the non-root user, then never log in as root again).
  • A text editor you're comfortable with (nano or vim).

Step 1 — Create a non-root user (3 min)

Log in as root (just this once):

ssh root@your-server-ip

Create a user with sudo:

adduser yourname
usermod -aG sudo yourname

Set up SSH key login for the new user:

mkdir -p /home/yourname/.ssh
cp ~/.ssh/authorized_keys /home/yourname/.ssh/
chown -R yourname:yourname /home/yourname/.ssh
chmod 700 /home/yourname/.ssh
chmod 600 /home/yourname/.ssh/authorized_keys

From a second terminal, verify you can log in as the new user:

ssh yourname@your-server-ip

If that works, close the root session. Going forward, log in only as your non-root user.

Step 2 — Disable root and password SSH (3 min)

As your non-root user with sudo:

sudo nano /etc/ssh/sshd_config

Set (or uncomment) these lines:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

Restart SSH:

sudo systemctl restart sshd

Test in a new terminal session before closing the current one. If the new connection works, you're done. If not, root/password SSH is still your recovery path.

Step 3 — Configure the firewall (3 min)

Ubuntu and Debian have ufw built in. Allow only what you need:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp       # SSH
sudo ufw allow 80/tcp       # HTTP
sudo ufw allow 443/tcp      # HTTPS
sudo ufw enable
sudo ufw status

If you've moved SSH to a non-standard port (step 6 below), substitute that port number for 22.

Step 4 — Install and configure fail2ban (4 min)

Fail2ban watches auth logs and automatically bans IPs that brute-force SSH or other services:

sudo apt update
sudo apt install fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Default config is adequate for most VPS. To view banned IPs after some time running:

sudo fail2ban-client status sshd

On a public VPS, you'll typically see several banned IPs within the first 24 hours — the internet's ambient SSH brute-force traffic.

Step 5 — Enable automated security updates (4 min)

On Ubuntu, unattended-upgrades handles security patches automatically:

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

Edit the config to enable the security repository:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Ensure this line is uncommented:

"${distro_id}:${distro_codename}-security";

Background security patches now apply automatically. For production systems where an upgrade could break application compatibility, test periodically rather than assuming patches are always safe.

Step 6 — Move SSH to a non-standard port (optional, 5 min)

Moving SSH to a non-standard port (e.g., 2222) doesn't add real security but reduces automated brute-force traffic by 99%+. Cleaner logs, less noise.

sudo nano /etc/ssh/sshd_config

Change:

Port 2222

Update ufw:

sudo ufw allow 2222/tcp
sudo ufw delete allow 22/tcp
sudo systemctl restart sshd

Test the new port in a new terminal before closing existing sessions:

ssh -p 2222 yourname@your-server-ip

If you're using a bastion or SSH config file, remember to update it.

Step 7 — Install monitoring (5 min)

Netdata is free, lightweight, and shows detailed real-time metrics:

bash <(curl -Ss https://my-netdata.io/kickstart.sh)

Allow its port through ufw if you want external access:

sudo ufw allow 19999/tcp

Access at http://your-server-ip:19999.

Alternative: use your VPS provider's built-in monitoring. DigitalOcean, Linode, and others show CPU/RAM/disk trends in their dashboards.

Step 8 — Set up provider snapshots (3 min)

In your VPS provider's dashboard:

  • DigitalOcean: Droplets → your Droplet → Backups → Enable (~20% of Droplet price).
  • Vultr: Instances → your instance → Settings → Auto Backups → Enable.
  • Linode: Linodes → your Linode → Backups → Enable.
  • Hetzner: Cloud Servers → your server → Backups → Enable.

For anything you care about staying available, skipping this costs far more than the $1-3/month it adds.

Summary — 30 minutes, big wins

At this point:

  • Root SSH login: disabled.
  • Password SSH: disabled (key-only).
  • Firewall: active, minimal exposure.
  • Brute-force protection: active.
  • Security patches: automatic.
  • SSH port: optionally moved (cleaner logs).
  • Monitoring: visible, trends captured.
  • Snapshots: automated, with recovery path.

You've eliminated maybe 95% of the default attack surface that a fresh public VPS exposes. Everything above is standard practice — the unusual thing is doing it consistently within the first 30 minutes, before you start installing applications that add their own surface area.

FAQ

Do I really need all this for a hobby VPS?

Yes. Public VPS instances are scanned constantly. Skipping this setup is the reason "my server got hacked" stories exist. The 30-minute investment prevents 95% of those stories.

Can I automate this for future VPS setups?

Yes — cloud-init user-data scripts or Ansible playbooks can execute all of the above automatically at provisioning. For any developer provisioning multiple VPS, automate once then reuse.

What about running services that need additional ports?

Add them to ufw as needed: sudo ufw allow 5432/tcp for Postgres, sudo ufw allow 3000/tcp for a dev server, etc. Only open what you actually need.

Is fail2ban enough or should I use something heavier?

For typical web VPS, fail2ban handles the 99%. For high-value production, layer additional tools: CrowdSec (community threat intelligence), Cloudflare WAF (edge filtering), ModSecurity (web-app firewall).

What's the cost impact of snapshots?

Typically 20% of instance cost. On a $6 DigitalOcean Droplet, that's $1.20/month. Trivial expense relative to the recovery time they save.

Last verified April 2026.