DEV Community

Cover image for How to Secure a VPS: The Complete Ubuntu Hardening Guide
Wade Thomas
Wade Thomas

Posted on

How to Secure a VPS: The Complete Ubuntu Hardening Guide

The moment a VPS gets a public IP, it's already being scanned. Automated bots start hammering the default root account with password guesses within minutes of the server going online — before you've even finished your first apt update.

This guide walks through the baseline hardening I run on every fresh Ubuntu server before deploying anything to it: creating a proper user account, locking down root, setting up a firewall, quieting bot noise on SSH, and auto-banning repeat offenders.

Prefer to follow along on video?

1. Stop Using the Root User

Every Linux server in the world ships with an account named root. That's the problem — hackers already know the username, so they only need to guess the password or find one exploit to get full control. A custom username forces an attacker to guess two unknowns instead of one.

A few other reasons to move off root:

  • No safety net. Root executes destructive commands instantly, no confirmation. Run rm -rf / as root and it's gone. A standard user needs sudo, which at least forces a pause and a password prompt.
  • Bots target root specifically. The moment a VPS goes online, automated bots start brute-forcing the root account with thousands of password guesses per minute. Disable root login and that entire attack surface disappears.
  • No accountability. If more than one person has server access, a shared root login makes it impossible to tell who did what. Individual sudo accounts get logged to /var/log/auth.log, so every command is tied to a specific user.

Create a sudo user

adduser your_username
usermod -aG sudo your_username
Enter fullscreen mode Exit fullscreen mode

-aG breaks down into two flags: -G adds the user to the group that follows (sudo), and -a (append) makes sure the user is added to that group rather than having all their other group memberships wiped out. Together, -aG says: add this user to sudo, keep everything else as-is.

Verify it worked:

groups your_username
Enter fullscreen mode Exit fullscreen mode

Lock down root

Log out of root and back in as your new sudo user first, then:

# Lock the root password
sudo passwd -l root

# Disable root login over SSH
sudo nano /etc/ssh/sshd_config
# set: PermitRootLogin no
sudo systemctl restart sshd

# Confirm root is locked
sudo passwd -S root
Enter fullscreen mode Exit fullscreen mode

2. Set Up a Firewall (UFW)

A firewall closes off everything you're not explicitly using. On a fresh VPS, that means:

  • Blocking brute-force attempts on ports you don't need exposed
  • Keeping internal-only services (databases, admin tools) off the public internet
  • Restricting sensitive ports like SSH to specific IPs, if needed
  • Dropping unexpected traffic, which softens basic DoS attempts
  • Closing the door on any hidden vulnerability in something you're running

Ubuntu ships with UFW (Uncomplicated Firewall), which blocks all incoming traffic by default and only opens what you explicitly allow:

# Allow SSH first so you don't lock yourself out
sudo ufw allow OpenSSH
# or: sudo ufw allow 22/tcp

# Allow web traffic if you're hosting a site
sudo ufw allow http
sudo ufw allow https

# Turn it on
sudo ufw enable

# Check status
sudo ufw status verbose
Enter fullscreen mode Exit fullscreen mode

3. Change the Default SSH Port

Within minutes of going live, bots start hammering port 22 — not targeted attacks, just scripts sweeping the internet for the default SSH port. Moving to something non-standard, like 2222, makes those scanners skip right past you.

sudo nano /etc/ssh/sshd_config
# uncomment #Port 22 and change it:
# Port 2222

sudo ufw allow 2222/tcp
sudo ufw reload
sudo systemctl restart sshd
Enter fullscreen mode Exit fullscreen mode

Worth being honest about this one: security researchers call this "security through obscurity," and on its own it's a weak measure — it doesn't make the server harder to break into. What it does do is keep your auth logs from being flooded with bot noise, which makes real suspicious activity much easier to spot. Pair it with SSH keys, disabled password auth, and Fail2Ban for actual hardening.

4. Install Fail2Ban

Fail2Ban watches your logs for repeated failed login attempts and temporarily bans the offending IP at the firewall level.

Why it's worth running:

  • Free, open-source, and quick to set up
  • Highly configurable — ban duration, whitelisted IPs, which services to watch
  • Bans happen at the firewall, so malicious traffic doesn't eat server resources
  • Can integrate with notifications for real-time alerts

Where it falls short:

  • Reactive, not preventive — it only acts after a set number of failed attempts have already happened
  • Can lock out legitimate users who fat-finger a password a few times in a row
  • Weak against distributed attacks, since it bans by IP and botnets rotate through thousands of them
  • Vulnerable to IP spoofing
  • Can conflict with Docker's iptables rules on a Docker host, causing bans to fail or hit the wrong container

Install it:

sudo apt update
sudo apt install fail2ban -y
sudo systemctl start fail2ban
sudo systemctl enable fail2ban
Enter fullscreen mode Exit fullscreen mode

(The -y flag auto-confirms every prompt during install — only use it once you're already certain about the package.)

Wrap-Up

None of these steps make a server unbreakable on their own — a sudo user, a firewall, an obscure SSH port, and Fail2Ban are each individually beatable. Stacked together, they cut off the low-effort, automated attacks that hit every public IP within minutes of going live, and they keep your logs clean enough that you'd actually notice something that isn't normal.

If you found this useful, the video above walks through each step live. Let me know in the comments if you run into anything setting this up on your own box.

Top comments (2)

Collapse
 
aldo_cve profile image
Aldo

These foundational steps – creating a sudo user, locking down root, UFW, changing SSH ports, and Fail2Ban – are absolutely critical for securing any new VPS. I've implemented these exact measures countless times across various projects, and they form the essential baseline for preventing a lot of common automated attacks that constantly scan the internet. It's a solid checklist for anyone serious about their server's security.

Where the real operational challenge begins for a SaaS setup is maintaining this security posture across multiple instances and over time. Manually repeating these steps quickly becomes a scalability bottleneck and a source of inconsistency. This is precisely why codifying your server configurations with tools like Ansible or Terraform, and managing them through version control, becomes indispensable. It turns server provisioning and security updates into repeatable, auditable processes, which is crucial for both reliability and rapid recovery scenarios.

It’s also important to remember that these steps primarily secure the host OS and network perimeter. For an actual SaaS application, the next critical layer is securing what's running on that VPS. This means configuring a robust reverse proxy like Nginx or Caddy with proper TLS termination, strong HTTP headers, rate limiting, and potentially integrating a Web Application Firewall. A strong application-level security posture is often where the most sophisticated attacks target, and it requires a different set of considerations beyond just the OS hardening.

Collapse
 
wadethomastt profile image
Wade Thomas

Thank you for you contribution to this post I welcome it and I'm very grateful. I'm using Traefik as my reverse proxy and I will cover, security measures that can be taken there. Thanks for suggesting Ansible and Terraform for the automated process, with the other security measures. Great Setup!