The moment your VPS goes online, it becomes a target. Automated bots scan the internet 24/7, probing for vulnerable servers with default configurations, weak passwords, and unpatched software. Without proper security measures, your server could be compromised within hours.
This guide provides a complete, actionable security checklist that takes your VPS from vulnerable to hardened in about an hour.
Why VPS Security Matters
- A new cyberattack occurs every 39 seconds
- The average unpatched server is compromised within 8 hours of going online
- Brute-force SSH attacks account for 65% of all server attacks
- The average cost of a data breach is $4.45 million (IBM, 2023)
The good news? Most attacks target low-hanging fruit - servers with default configurations and weak passwords. By following this guide, you'll be ahead of 90% of servers on the internet.
Step 1: Initial Server Hardening
Update Everything
# Update package lists and upgrade all packages
sudo apt update && sudo apt upgrade -y
# Install security updates only
sudo apt install unattended-upgrades -y
# Remove unused packages
sudo apt autoremove -y
Create a Non-Root User
Never use root for daily operations. Create a dedicated admin user:
# Create new user
sudo adduser admin
# Add to sudo group
sudo usermod -aG sudo admin
# Verify sudo access
su - admin
sudo whoami # Should output: root
Set Proper Hostname
# Set a meaningful hostname
sudo hostnamectl set-hostname myserver
# Update /etc/hosts
echo "127.0.1.1 myserver" | sudo tee -a /etc/hosts
Step 2: SSH Security (Most Critical)
SSH is the #1 attack vector for VPS servers. These steps dramatically reduce your attack surface.
Set Up SSH Key Authentication
# On your LOCAL machine, generate an SSH key pair
ssh-keygen -t ed25519 -C "your_email@example.com"
# Copy public key to server
ssh-copy-id admin@your_server_ip
# Test key-based login
ssh admin@your_server_ip
Harden SSH Configuration
# Edit SSH configuration
sudo nano /etc/ssh/sshd_config
# Apply these security settings:
Port 2222 # Change from default 22
PermitRootLogin no # Disable root login
PasswordAuthentication no # Disable password auth (keys only)
PubkeyAuthentication yes # Enable key authentication
MaxAuthTries 3 # Limit login attempts
ClientAliveInterval 300 # Timeout idle sessions
ClientAliveCountMax 2 # Max keepalive messages
X11Forwarding no # Disable X11
AllowUsers admin # Only allow specific users
Protocol 2 # Use SSH protocol 2 only
# Test configuration before restarting
sudo sshd -t
# Restart SSH
sudo systemctl restart sshd
ssh -p 2222 admin@your_server_ip. If it works, close the old session. If not, use the old session to fix the configuration.
Step 3: Firewall Configuration (UFW)
# Install UFW (usually pre-installed)
sudo apt install ufw -y
# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (on your custom port)
sudo ufw allow 2222/tcp comment 'SSH'
# Allow web traffic
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
# Rate limit SSH to prevent brute force
sudo ufw limit 2222/tcp
# Enable the firewall
sudo ufw enable
# Check status
sudo ufw status verbose
Step 4: Install and Configure Fail2Ban
Fail2Ban monitors log files and automatically bans IP addresses that show malicious behavior (like repeated failed login attempts).
# Install Fail2Ban
sudo apt install fail2ban -y
# Create local configuration
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Configure the jail settings:
[DEFAULT]
bantime = 3600 # Ban for 1 hour
findtime = 600 # Within 10 minutes
maxretry = 3 # After 3 failed attempts
banaction = ufw # Use UFW for banning
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400 # Ban SSH attackers for 24 hours
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
[nginx-badbots]
enabled = true
filter = nginx-badbots
logpath = /var/log/nginx/access.log
maxretry = 2
# Restart Fail2Ban
sudo systemctl restart fail2ban
sudo systemctl enable fail2ban
# Check banned IPs
sudo fail2ban-client status sshd
# Unban an IP if needed
sudo fail2ban-client set sshd unbanip 192.168.1.100
Step 5: Automatic Security Updates
# Install unattended-upgrades
sudo apt install unattended-upgrades apt-listchanges -y
# Configure automatic updates
sudo dpkg-reconfigure -plow unattended-upgrades
# Edit configuration for security-only updates
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Ensure these lines are uncommented:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
# Verify it's working
sudo unattended-upgrade --dry-run --debug
Step 6: SSL/TLS Everything
# Install Certbot for free SSL
sudo apt install certbot python3-certbot-nginx -y
# Get SSL certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Set up auto-renewal
sudo certbot renew --dry-run
# Force HTTPS in Nginx (Certbot usually does this automatically)
# Add to server block:
# if ($scheme != "https") {
# return 301 https://$host$request_uri;
# }
Harden SSL Configuration
# Add to Nginx server block for A+ SSL rating:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
# Security headers
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Step 7: Intrusion Detection
Install AIDE (Advanced Intrusion Detection Environment)
# Install AIDE
sudo apt install aide -y
# Initialize the database
sudo aideinit
# Copy the new database
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# Run a check (do this regularly or via cron)
sudo aide --check
# Set up daily check via cron
echo "0 4 * * * /usr/bin/aide --check | mail -s 'AIDE Report' admin@yourdomain.com" | sudo crontab -
Install rkhunter (Rootkit Hunter)
# Install rkhunter
sudo apt install rkhunter -y
# Update the database
sudo rkhunter --update
# Run a scan
sudo rkhunter --check --skip-keypress
# Automate weekly scans
echo "0 3 * * 0 /usr/bin/rkhunter --check --skip-keypress --report-warnings-only" | sudo crontab -
Step 8: Log Monitoring
# Important log files to monitor:
# /var/log/auth.log - Authentication attempts
# /var/log/syslog - System messages
# /var/log/nginx/ - Web server logs
# /var/log/fail2ban.log - Banned IPs
# Quick security check commands:
# Failed SSH login attempts
grep "Failed password" /var/log/auth.log | tail -20
# Successful logins
grep "Accepted" /var/log/auth.log | tail -20
# Currently banned IPs
sudo fail2ban-client status sshd
# Open connections
ss -tulnp
Step 9: Regular Backups
# Create a backup script
sudo nano /usr/local/bin/backup.sh
#!/bin/bash
DATE=$(date +%Y%m%d)
BACKUP_DIR="/backups"
# Create backup directory
mkdir -p $BACKUP_DIR
# Backup website files
tar -czf $BACKUP_DIR/website-$DATE.tar.gz /var/www/
# Backup databases
mysqldump --all-databases > $BACKUP_DIR/databases-$DATE.sql
# Backup configurations
tar -czf $BACKUP_DIR/configs-$DATE.tar.gz /etc/nginx/ /etc/ssh/ /etc/fail2ban/
# Delete backups older than 30 days
find $BACKUP_DIR -type f -mtime +30 -delete
echo "Backup completed: $DATE"
# Make executable
sudo chmod +x /usr/local/bin/backup.sh
# Schedule daily backup at 2 AM
echo "0 2 * * * /usr/local/bin/backup.sh" | sudo crontab -
Complete VPS Security Checklist
| Task | Priority | Difficulty | Time |
|---|---|---|---|
| Update all packages | Critical | Easy | 5 min |
| Create non-root user | Critical | Easy | 2 min |
| Disable root SSH login | Critical | Easy | 2 min |
| Set up SSH key authentication | Critical | Medium | 10 min |
| Disable password authentication | Critical | Easy | 2 min |
| Change SSH port | High | Easy | 2 min |
| Configure UFW firewall | Critical | Easy | 5 min |
| Install Fail2Ban | High | Medium | 10 min |
| Enable automatic updates | High | Easy | 5 min |
| Install SSL certificates | High | Easy | 5 min |
| Harden SSL configuration | Medium | Medium | 10 min |
| Set file permissions | High | Easy | 5 min |
| Install AIDE | Medium | Medium | 10 min |
| Install rkhunter | Medium | Easy | 5 min |
| Set up backup script | High | Medium | 15 min |
| Configure log monitoring | Medium | Medium | 10 min |
Common Security Mistakes to Avoid
- Using root for everything - Always use a non-root user with sudo
- Weak passwords - Use 16+ character passwords or SSH keys
- Not updating software - Enable automatic security updates
- Leaving default SSH port - Change port 22 to reduce automated attacks
- Opening unnecessary ports - Only expose ports you actively use
- No backups - Set up automated daily backups
- Ignoring logs - Monitor auth.log and fail2ban regularly
- Running outdated software - Keep Nginx, PHP, MySQL updated
- No firewall - Always configure UFW or iptables
- Storing secrets in code - Use environment variables for passwords and API keys
Frequently Asked Questions
How quickly can an unsecured VPS get hacked?
An unsecured VPS with default settings and a weak root password can be compromised within hours. Automated bots continuously scan the internet for vulnerable servers. SSH brute-force attacks typically start within minutes of a server going online.
Is changing the SSH port really effective?
Yes. While it's "security through obscurity" and not a replacement for real security, changing the SSH port from 22 reduces automated brute-force attacks by over 99%. Combined with key-based authentication and Fail2Ban, it makes your server very resistant to SSH attacks.
Should I use a VPN to access my VPS?
For additional security, yes. A VPN adds another layer by hiding your SSH port from the public internet. You can configure UFW to only allow SSH connections from your VPN IP address.
How often should I check my server security?
Run automated checks daily (AIDE, rkhunter, fail2ban logs) and do a manual review weekly. Check for available updates, review authentication logs, and verify backup integrity at least once a month.
What should I do if my VPS is compromised?
Immediately: 1) Disconnect the server from the network, 2) Change all passwords, 3) Analyze logs to understand the breach, 4) Restore from a clean backup, 5) Apply all security measures from this guide before bringing it back online.
Can VPS Commander help with security?
Yes! VPS Commander includes security-focused workflows for firewall configuration, log monitoring, and server management. You can view authentication logs, check server status, and manage configurations through a visual interface.
Conclusion
Securing your VPS is not optional - it's the first thing you should do after provisioning a new server. The steps in this guide - SSH hardening, firewall configuration, Fail2Ban, automatic updates, and intrusion detection - create multiple layers of defense that make your server extremely resistant to common attacks.
Remember: security is not a one-time task. Keep your software updated, monitor your logs regularly, and test your backups. The hour you spend securing your VPS today can save you from days of recovery after a breach.