VPS Security Best Practices: A Practical Hardening Guide

May 11, 2026 · Rich, CutVPS · 7 min read

The Reality of VPS Security

VPS security best practices aren't about paranoia — they're about handling the threats that actually happen. A fresh VPS on a public IP address will receive brute-force SSH login attempts within hours of provisioning. Not days. Hours. Automated bots scan the entire IPv4 range constantly, trying default credentials on every server they find.

The good news: the most common attacks are also the easiest to stop. Nine steps, about 30 minutes of work, and your VPS goes from "sitting duck" to "not worth the effort" for the vast majority of attackers.

This guide assumes you're running Linux (Ubuntu or Debian). If you need the basics of getting started first, read our VPS setup guide — it covers the foundation that this post builds on.

1. SSH Keys and Disable Root

This is the single most important security measure on any VPS. It eliminates the most common attack vector entirely.

Generate an SSH key pair on your local machine (if you haven't already):

ssh-keygen -t ed25519 -C "your-email@example.com"

Copy it to your server and then lock down SSH:

ssh-copy-id youruser@your-server-ip

Edit /etc/ssh/sshd_config and set:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3

Restart SSH: sudo systemctl restart sshd

With these settings, attackers can hammer your SSH port all day — without the private key, they're not getting in. It's the difference between a locked door and an open one.

2. Firewall: Block Everything by Default

The philosophy is simple: deny all incoming traffic, then explicitly allow only what you need.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

That opens SSH (22), HTTP (80), and HTTPS (443). If your application uses other ports (database, Redis, custom APIs), add them individually. Every port you don't open is one less thing to worry about.

Check your rules with sudo ufw status verbose. If a port doesn't need to be public, it shouldn't be.

3. Automatic Security Updates

Unpatched software is the second most common attack vector after weak credentials. Set up automatic security patches:

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

This installs critical security updates automatically without restarting services or requiring your attention. Major version upgrades still need manual review — but security patches shouldn't wait for you to remember to run apt upgrade.

Check it's working with sudo unattended-upgrades --dry-run.

4. Fail2Ban for Brute-Force Protection

Even with SSH keys, failed login attempts generate log noise and waste resources. Fail2Ban watches your logs and temporarily bans IPs that fail too many login attempts.

sudo apt install fail2ban -y

Create a local config that won't be overwritten by updates:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Edit /etc/fail2ban/jail.local and set sensible defaults:

[sshd]
enabled = true
port = ssh
maxretry = 3
bantime = 3600
findtime = 600

This bans any IP that fails 3 login attempts within 10 minutes, for 1 hour. Restart the service: sudo systemctl restart fail2ban

Check banned IPs with sudo fail2ban-client status sshd. You'll be surprised how quickly the list grows — a reminder of why SSH keys matter.

5. Change the Default SSH Port

This is security through obscurity — it won't stop a targeted attacker, but it eliminates 99% of automated scanning bots that only try port 22. It's five seconds of work for a massive reduction in log noise.

Edit /etc/ssh/sshd_config:

Port 2222

Update your firewall before restarting SSH:

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

Pick any port above 1024 and below 65535. Connect with ssh -p 2222 youruser@your-ip going forward. Add it to your SSH config file (~/.ssh/config) so you don't have to remember it every time.

6. Principle of Least Privilege

Don't run applications as root. Every service should run as its own user with only the permissions it needs.

If your application gets compromised (and you should assume it eventually might), running as a limited user means the damage is contained to that user's permissions — not the entire system.

7. SSL Everything

There's no excuse for running anything over plain HTTP in 2026. Let's Encrypt certificates are free and auto-renewing.

sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Certbot handles the certificate, configures Nginx to redirect HTTP to HTTPS, and sets up auto-renewal. Test it with sudo certbot renew --dry-run.

Don't forget internal services too. If your database accepts connections from other servers, those connections should be encrypted. If your application talks to a Redis instance, use TLS. Encryption isn't just for the public-facing parts.

8. Automated Backups

Security includes disaster recovery. Your VPS provider does server-level snapshots (we do), but your application data is your responsibility.

A basic backup script that runs daily via cron:

# /opt/scripts/backup.sh
tar czf /tmp/backup-$(date +%Y%m%d).tar.gz /var/www /etc/nginx /etc/letsencrypt
rclone copy /tmp/backup-$(date +%Y%m%d).tar.gz remote:backups/
rm /tmp/backup-$(date +%Y%m%d).tar.gz

rclone can push backups to S3, Backblaze B2, Google Cloud Storage, or any cloud storage provider. The key principles:

Database backups need their own step. For MySQL: mysqldump --all-databases > /tmp/db-backup.sql. For PostgreSQL: pg_dumpall > /tmp/db-backup.sql. Add these to your backup script before the tar command.

9. Monitoring and Alerts

You can't fix what you don't know about. At minimum, monitor these:

At CutVPS, we run 24/7 automated monitoring on every server — if your VPS goes down at 3am, we know before you do. But application-level monitoring is your responsibility. Tools like Uptime Robot (free tier), Hetrix Tools, or a simple cron script that posts to a Discord webhook cover the basics.

Frequently Asked Questions

How often should I update my VPS?

Security patches should be applied as soon as they're available — ideally automatically via unattended-upgrades. For major version updates, test in a staging environment first, but don't wait more than a week for critical security fixes.

Is a VPS secure by default?

No. A fresh VPS comes with root login enabled, password authentication on, no firewall rules, and no intrusion detection. The first 15 minutes after provisioning should be spent on the basics: SSH keys, disable root login, firewall, and automatic updates.

Do I need antivirus on a Linux VPS?

Generally no. Linux servers don't need traditional antivirus the way Windows machines do. Focus instead on keeping software updated, running a firewall, using fail2ban for brute-force protection, and scanning for rootkits with tools like rkhunter or chkrootkit if you're concerned.

How do I know if my VPS has been hacked?

Warning signs include unexpected CPU usage, unknown processes running, modified system files, new user accounts you didn't create, unusual outbound network traffic, and log entries showing successful logins from unfamiliar IPs. Automated monitoring catches most of these before you'd notice them manually.

What's the most important VPS security step?

SSH key authentication with password login disabled. This single step eliminates the most common attack vector — brute-force password attempts. A fresh VPS on a public IP will receive thousands of login attempts within hours. SSH keys make all of them fail instantly.

R

Rich

Founder, CutVPS

Infrastructure nerd who got tired of overpaying for servers. Built CutVPS to prove that automation beats headcount and that honest pricing beats marketing budgets. Writes about VPS hosting, server management, and cutting through industry nonsense.

Secure VPS hosting from $15/month. KVM isolation, NVMe storage, 24/7 monitoring included.

View Plans