VPS configuration is the same first hour on every fresh Ubuntu box: update the system, create a non-root user, lock down SSH, turn on a firewall, install fail2ban, and only then install whatever you actually rented the server to run.
Skip any of these steps and the server still boots. It just boots as a target - a fresh Ubuntu VPS on a public IP gets scanned and probed within minutes of coming online, and the difference between a hardened box and a default one is entirely in this checklist.
Table of contents
- Update the system and set the basics first
- Create a non-root sudo user and switch off root login
- SSH keys, and disabling password authentication
- Turn on ufw and install fail2ban
- Unattended upgrades, swap, and the things people forget
- Web server, TLS, backups, and monitoring - then you are actually done
- How this fits the rest of the stack
- FAQ
Update the system and set the basics first
Before anything else, pull the latest package lists and apply updates. A brand-new VPS image is often weeks or months old by the time you provision it, and some of the gap is security patches.
sudo apt update && sudo apt upgrade -y
sudo timedatectl set-timezone UTC
timedatectl status
Set the timezone to UTC (or your actual operating timezone, deliberately) before anything writes a timestamped log - reconciling logs across servers in different timezones later is a needless headache. Confirm NTP is syncing; most cloud images have it enabled by default via systemd-timesyncd, but it is worth the one command to check.
It is also worth checking which Ubuntu LTS release you are on and roughly how long it has left of standard support, since planning an upgrade path before you are forced into one avoids doing this whole checklist again under time pressure a year later on an end-of-life box.
Create a non-root sudo user and switch off root login
Operating as root by default means every mistake, every compromised credential, and every misconfigured script has full system access with no friction in between. Create a real user, grant it sudo, and stop logging in as root entirely.
adduser deploy
usermod -aG sudo deploy
su - deploy
Once the new user can sudo successfully, disable root login over SSH in the next step. There is no legitimate daily workflow that requires SSHing in directly as root on a server you administer yourself.
SSH keys, and disabling password authentication
Password-based SSH is the single most attacked surface on a public IP. Generate a key pair on your own machine, copy the public key to the server, then disable password login entirely so a leaked or guessed password cannot be used to get in at all.
# on your local machine
ssh-copy-id [email protected]
# on the server, edit /etc/ssh/sshd_config
sudo nano /etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
Restart sshd after saving, and critically, test the new key-based login in a second terminal before closing your current session. Locking yourself out of a remote box because sshd_config had a typo is a well-known way to lose an afternoon.
sudo systemctl restart sshd
Turn on ufw and install fail2ban
A firewall that defaults to deny and explicitly allows only what you need is worth more than most other hardening steps combined. ufw is a thin, readable wrapper over iptables that makes this approachable.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verbose
fail2ban watches log files for repeated failed login attempts and temporarily bans the offending IP at the firewall level. It will not stop a targeted, patient attacker, but it silences the constant background noise of automated SSH scanners within minutes of being enabled.
sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Test the firewall rule set before you walk away from the session, the same way you tested SSH key login earlier. Run ufw status verbose and confirm OpenSSH is explicitly allowed and the default policy denies incoming, then open a second terminal and reconnect over SSH to prove the rule set does not lock out your own session before you add anything else to it.
Unattended upgrades, swap, and the things people forget
Security patches you apply manually are patches you apply late. unattended-upgrades installs security updates automatically in the background, which matters most on the boxes you check on least often.
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades
Add swap on any VPS with 2GB of RAM or less - a single memory-hungry process (a build step, an ill-tuned database) without swap does not slow down gracefully, it gets killed by the OOM killer or freezes the box entirely.
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
It is worth deciding upfront whether unattended-upgrades should also reboot automatically when a kernel update requires it, or just install the package and leave the reboot to you. Automatic reboots keep the kernel patched without you remembering to do it, but they can restart a server mid-task if you are not also running a process manager that brings your services back up cleanly afterward.
Web server, TLS, backups, and monitoring - then you are actually done
Only after the steps above should you install whatever the box is actually for: a reverse proxy like Nginx or Caddy in front of your app, a certificate from Let’s Encrypt bound to a real domain, and a process manager so your app restarts on crash or reboot rather than staying down silently.
- Caddy handles TLS certificate issuance and renewal automatically, which removes an entire recurring task from this list
- Point off-server backups at anything that holds state - a database, uploaded files - not just the application code, which usually lives in git anyway
- Add basic uptime monitoring from outside the server; a box can be running while the service it hosts is silently down
This is also the point where the honest comparison to a managed platform is worth making. Every item on this list - the firewall, fail2ban, unattended upgrades, the TLS renewal cron, the backup schedule, the monitoring - is maintenance you now own indefinitely, on every VPS you run, forever, not a one-time setup cost.
Log rotation is the other item people forget until a full disk takes the server down. Ubuntu ships logrotate by default for most system logs, but application logs your own service writes need their own rotation rule, or a busy app can fill the disk with logs alone within weeks, taking the whole server offline for a reason that has nothing to do with traffic or attacks.
How this fits the rest of the stack
None of this is difficult individually, but it is a real, recurring maintenance surface across however many servers you run, and it grows linearly with your infrastructure rather than staying fixed. If part of the appeal of a VPS was never actually the shell access, and what you wanted was a place to deploy code, the RunxBuild hosting calculator shows what a managed service or database costs when someone else owns this checklist instead of you.
If you would rather skip the hardening entirely, the same app can run as a service from the RunxBuild dashboard, with no SSH port to lock down and no unattended-upgrades to babysit.
Useful related references:
- VPS Price: What Drives It, and the Line Items That Are Not On It
- VPS Website Hosting: What You Get, What You Maintain, and the Setup That Actually Works
- Managed VPS: What It Actually Covers, What It Doesn’t, and a Checklist
- Services on RunxBuild
FAQ
What is the first thing I should do after getting a new VPS?
Update the system, create a non-root user with sudo access, and set up SSH key authentication before doing anything else. Those three steps close the most commonly exploited gaps on a freshly provisioned server before it has even had a chance to be scanned.
Do I really need a firewall if my VPS provider already has one?
Yes, if the provider offers a network-level firewall use it as a second layer, but still run ufw or an equivalent on the host itself. Defense in depth matters here - a misconfigured provider firewall rule should not be the only thing standing between your server and the internet.
Is fail2ban necessary if I already disabled password authentication?
It is still worth running. Disabling password auth stops brute-force logins from succeeding, but fail2ban also reduces the noise and resource cost of constant automated login attempts hitting your server, and it covers other services beyond SSH if you configure additional jails.
How much swap does a VPS need?
A common rule of thumb is swap equal to your RAM up to about 4GB, and roughly half your RAM beyond that. The goal is not to run workloads in swap permanently - it is slow - but to give the kernel headroom so a memory spike does not immediately kill your process.
What is the difference between VPS configuration and VPS management?
Configuration is the one-time first-hour setup covered here. Management is everything that follows: applying updates over time, renewing certificates, watching disk space, rotating logs, and responding when something breaks at 2am. Configuration ends; management does not.