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.
- Web servers — Nginx runs as
www-databy default. Don't change that. - Databases — MySQL runs as
mysql, PostgreSQL aspostgres. Again, leave them alone. - Your application — create a dedicated user:
sudo adduser --system --no-create-home myapp - File permissions — web files should be owned by your deploy user, readable by the web server user. Not writable by the web server unless absolutely necessary.
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:
- Automate it — if it requires you to remember, it won't happen
- Store offsite — backups on the same server that fails aren't backups
- Test restores — a backup you've never restored from is a prayer, not a backup
- Include everything — database dumps, SSL certificates, Nginx configs, application code
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:
- Uptime — is your server responding? Set up a simple HTTP check that pings your site every 5 minutes.
- Disk usage — servers don't crash gracefully when the disk fills up. Alert at 80%, panic at 90%.
- CPU and RAM — sustained high usage means either traffic growth (good) or a runaway process (bad). Either way, you want to know.
- Failed login attempts — check
/var/log/auth.logperiodically, or let fail2ban handle the alerts. - SSL certificate expiry — Certbot handles renewals, but set up an alert for 14 days before expiry just in case the renewal fails.
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.