VPS Security Hardening Checklist: 10 Steps to Protect Your Server in 2025

VPS Security Hardening Checklist: 10 Steps to Protect Your Server in 2025

A freshly deployed VPS is not a secure VPS. The moment your server gets a public IP address, automated bots begin scanning it — probing for open ports, attempting SSH brute-force logins, and looking for known vulnerabilities. This isn’t paranoia; it’s the documented reality of internet-facing infrastructure.

The good news: hardening a VPS against the vast majority of attacks takes less than an hour and requires no advanced security expertise. This checklist covers the 10 most impactful steps you can take to protect a Linux VPS in 2025 — in order of importance, with copy-paste commands for Ubuntu and Debian.

Before You Start

This guide assumes you have:

  • A KVM VPS running Ubuntu 22.04 or 24.04 LTS
  • Root or sudo access via SSH
  • A non-root sudo user created (we’ll create one in Step 2 if you haven’t)

Work through these steps in order — some steps depend on previous ones. Most importantly, do not lock yourself out: keep your SSH session open while testing changes, and always have VNC console access available as a fallback (available in VPS.DO’s SolusVM control panel).

💡 VPS.DO Tip: All VPS.DO plans include VNC console access via SolusVM — your emergency backdoor if SSH becomes unreachable during hardening. View VPS Plans →


Step 1: Update Everything Immediately

The single most impactful security action you can take is ensuring your system has all current patches. Many high-profile server compromises exploit known vulnerabilities that were patched months or years earlier — on systems that simply weren’t updated.

sudo apt update && sudo apt upgrade -y
sudo apt autoremove -y
sudo apt autoclean

Check your Ubuntu version and kernel:

lsb_release -a
uname -r

If a kernel update was installed, reboot to load the new kernel:

sudo reboot

Step 2: Create a Non-Root Sudo User

Working as root is dangerous — a typo or compromised session has unlimited destructive potential. Create a dedicated admin user and disable direct root login:

# Create a new user (replace 'adminuser' with your chosen username)
sudo adduser adminuser

# Grant sudo privileges
sudo usermod -aG sudo adminuser

# Switch to the new user to test
su - adminuser
sudo whoami  # Should output: root

From this point forward, use adminuser for all SSH connections. Root login will be disabled in Step 4.


Step 3: Configure SSH Key Authentication

Password-based SSH authentication is vulnerable to brute-force attacks. SSH key pairs are cryptographically secure and effectively immune to brute-force. This is the single most important SSH hardening step.

Generate a key pair on your local machine (not the VPS)

# On your local machine (Mac/Linux terminal or Windows PowerShell)
ssh-keygen -t ed25519 -C "your-email@example.com" -f ~/.ssh/vps_key

Ed25519 is the modern, recommended algorithm — smaller and more secure than RSA.

Copy the public key to your VPS

# From your local machine
ssh-copy-id -i ~/.ssh/vps_key.pub adminuser@YOUR_VPS_IP

# Or manually:
cat ~/.ssh/vps_key.pub | ssh adminuser@YOUR_VPS_IP "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Test key-based login before disabling passwords

ssh -i ~/.ssh/vps_key adminuser@YOUR_VPS_IP

Confirm you can log in successfully before proceeding. ✅


Step 4: Harden SSH Configuration

Now lock down the SSH daemon to eliminate the most common attack vectors:

sudo nano /etc/ssh/sshd_config

Make the following changes (find and modify existing lines, or add them if absent):

# Change SSH port (reduces automated scan noise)
Port 2222

# Disable root login entirely
PermitRootLogin no

# Disable password authentication (keys only)
PasswordAuthentication no
ChallengeResponseAuthentication no

# Disable empty passwords
PermitEmptyPasswords no

# Limit login attempts
MaxAuthTries 3

# Disconnect idle sessions after 10 minutes
ClientAliveInterval 600
ClientAliveCountMax 0

# Only allow specific users to SSH (replace with your username)
AllowUsers adminuser

# Disable X11 forwarding (not needed on a server)
X11Forwarding no

# Use only modern, secure algorithms
Protocol 2

Restart SSH — but keep your current session open while opening a new terminal to test the new configuration:

sudo systemctl restart sshd

In a new terminal, test the connection with the new port:

ssh -i ~/.ssh/vps_key -p 2222 adminuser@YOUR_VPS_IP

Only close your original session once the new connection works. ✅


Step 5: Configure the Firewall (UFW)

UFW (Uncomplicated Firewall) provides an easy interface to manage iptables rules. The principle: deny everything by default, allow only what you explicitly need.

# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH on your custom port
sudo ufw allow 2222/tcp

# Allow web traffic (if running a web server)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable the firewall
sudo ufw enable

# Verify rules
sudo ufw status verbose

Only open ports you actively use. Every open port is an additional attack surface.

Common port rules reference

# MySQL (only if remote connections are needed — prefer localhost-only)
sudo ufw allow 3306/tcp

# WireGuard VPN
sudo ufw allow 51820/udp

# Custom application port
sudo ufw allow 8080/tcp

# Remove a rule
sudo ufw delete allow 8080/tcp

Step 6: Install and Configure Fail2ban

Even with SSH keys required, bots will still hammer your SSH port with connection attempts. Fail2ban monitors log files and automatically bans IP addresses that show malicious behavior — too many failed login attempts, port scans, and similar patterns.

sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Create a local configuration file (override defaults without editing the main config):

sudo nano /etc/fail2ban/jail.local
[DEFAULT]
# Ban IPs for 1 hour after 5 failures within 10 minutes
bantime  = 3600
findtime = 600
maxretry = 5
backend  = systemd

[sshd]
enabled  = true
port     = 2222
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 3
bantime  = 86400  # 24 hours for SSH failures

[nginx-http-auth]
enabled = true

[nginx-botsearch]
enabled  = true
port     = http,https
logpath  = /var/log/nginx/error.log
sudo systemctl restart fail2ban

Monitor bans in real time:

sudo fail2ban-client status sshd

Step 7: Enable Automatic Security Updates

Manually updating a server is easy to forget. The unattended-upgrades package automatically installs security patches — arguably the most low-effort, high-impact security measure available.

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

Select “Yes” when prompted. To verify it’s configured correctly:

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

Ensure this line is uncommented:

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

Enable automatic updates and upgrades:

sudo nano /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";

Step 8: Disable Unused Services and Daemons

Every running service is a potential attack vector. Remove or disable anything you don’t need:

# List all running services
sudo systemctl list-units --type=service --state=running

# Check which services are listening on network ports
sudo ss -tlnp

# Disable a service (example: cups printing service — useless on a server)
sudo systemctl stop cups
sudo systemctl disable cups
sudo systemctl mask cups

Common services to consider disabling on a typical web server:

  • cups — Printing service (not needed)
  • avahi-daemon — Network discovery (not needed on a server)
  • bluetooth — Bluetooth (not needed)
  • snapd — Snap package manager (if you don’t use snaps)
# Remove snapd entirely if not using it (saves RAM and reduces attack surface)
sudo systemctl stop snapd
sudo apt purge snapd -y

Step 9: Secure Shared Memory

The /run/shm shared memory filesystem can be used by attackers to execute malicious code. Mount it with restricted options to prevent this:

sudo nano /etc/fstab

Add this line at the bottom:

tmpfs /run/shm tmpfs defaults,noexec,nosuid,nodev 0 0

Apply without rebooting:

sudo mount -o remount /run/shm

Also restrict /tmp to prevent execution of uploaded scripts:

sudo nano /etc/fstab
tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev 0 0

Step 10: Install a Rootkit and Malware Scanner

Automated scanning catches infections you’d otherwise miss. Install two complementary tools:

rkhunter (Rootkit Hunter)

sudo apt install rkhunter -y

# Initialize the baseline database
sudo rkhunter --update
sudo rkhunter --propupd

# Run a full scan
sudo rkhunter --check --sk

chkrootkit

sudo apt install chkrootkit -y
sudo chkrootkit

Schedule weekly scans with Cron

sudo crontab -e
# Run rkhunter every Sunday at 3 AM, email results
0 3 * * 0 /usr/bin/rkhunter --check --sk --report-warnings-only | mail -s "rkhunter report $(hostname)" you@youremail.com

Bonus: Additional Hardening for Production Servers

If you’re running a production server, consider these additional measures beyond the core 10 steps:

Enable Two-Factor Authentication for SSH

sudo apt install libpam-google-authenticator -y
google-authenticator  # Follow prompts, scan QR code with authenticator app

Then configure PAM to require 2FA:

sudo nano /etc/pam.d/sshd

Add at the top:

auth required pam_google_authenticator.so

And in /etc/ssh/sshd_config:

ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

Install a Web Application Firewall (ModSecurity + Nginx)

sudo apt install libnginx-mod-security2 -y

Set up log monitoring with Logwatch

sudo apt install logwatch -y

Logwatch sends daily email summaries of your server logs — SSH logins, failed attempts, service restarts, and more.

Enable auditd for system call auditing

sudo apt install auditd -y
sudo systemctl enable auditd
sudo systemctl start auditd

Security Hardening Checklist Summary

# Step Priority Time
1 Update all packages 🔴 Critical 2 min
2 Create non-root sudo user 🔴 Critical 2 min
3 Configure SSH key authentication 🔴 Critical 5 min
4 Harden SSH config (disable password auth, change port) 🔴 Critical 5 min
5 Configure UFW firewall 🔴 Critical 5 min
6 Install and configure Fail2ban 🟠 High 5 min
7 Enable automatic security updates 🟠 High 3 min
8 Disable unused services 🟡 Medium 10 min
9 Secure shared memory 🟡 Medium 3 min
10 Install rootkit scanner 🟡 Medium 5 min

Total time: approximately 45 minutes for a fully hardened VPS.


Final Thoughts

VPS security hardening is not a one-time task — it’s an ongoing practice. But the steps in this guide establish a strong baseline that addresses the most common attack vectors and dramatically reduces your server’s exposure. SSH keys, a properly configured firewall, Fail2ban, and automatic updates together eliminate the majority of real-world VPS compromises.

Run through this checklist on every new VPS you deploy. Better yet, turn it into a setup script so hardening becomes automatic on every new server. Your future self will thank you the first time a brute-force campaign targets your IP and finds nothing to attack.

All VPS.DO KVM VPS plans come with full root access and VNC console fallback — everything you need to implement this checklist safely. View USA VPS Plans →

Need help with a specific security configuration? VPS.DO’s support team is available 24/7 →


Related articles you might find useful:

 

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!