Overview
A newly provisioned VPS is a blank canvas — and an attractive target. Automated bots scan IP ranges constantly, probing for weak SSH passwords and unpatched services. Hardening your VPS isn’t paranoia; it’s basic hygiene.
This guide covers the essential hardening steps for an Ubuntu/Debian VPS. Each step is practical and has clear rationale.
Time required: 30-60 minutes Servers: Any Linux VPS (tested on Ubuntu 22.04 LTS)
1. Update the System
Before anything else, bring the system fully up to date:
sudo apt update && sudo apt upgrade -y
sudo reboot
Rebooting ensures you’re running on the latest kernel and base packages.
2. Create a Standard User
Never use root for daily administration. Create a standard user with sudo access:
# Create new user
sudo adduser aaron
# Add to sudo group
sudo usermod -aG sudo aaron
# Switch to the new user
sudo su - aaron
From now on, use sudo for administrative tasks.
3. Configure SSH Keys
Password authentication is a liability. SSH keys are much stronger.
On Your Local Machine
Generate a new ED25519 key (stronger and faster than RSA):
ssh-keygen -t ed25519 -C "aaron@workstation"
Save it to ~/.ssh/id_ed25519. Set a strong passphrase.
Add the Key to the Server
# Copy public key to server
ssh-copy-id -i ~/.ssh/id_ed25519.pub aaron@your-server-ip
You’ll be prompted for the user’s password once, then the key is installed.
Disable Password Authentication
# Edit SSH config
sudo nano /etc/ssh/sshd_config
Set these values:
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
MaxAuthTries 3
Then restart SSH:
sudo systemctl restart sshd
Before logging out: Test that passwordless authentication works in a new terminal. If you lock yourself out, you can recover via the provider’s console.
4. Install and Configure UFW (Firewall)
Ubuntu’s Uncomplicated Firewall (UFW) makes firewall management simple.
# Default deny incoming, allow outgoing
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (specific port to avoid lockout)
sudo ufw allow 22/tcp comment 'SSH'
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
# Enable the firewall
sudo ufw enable
Verify the rules:
sudo ufw status verbose
Only the ports you explicitly allow will accept connections. This blocks all the scanning bots probing random ports.
5. Enable Automatic Security Updates
Unattended security updates prevent you from running vulnerable software:
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades
The configuration tool will ask if you want to enable automatic updates. Select Yes.
Verify it’s active:
systemctl status unattended-upgrades.service
6. Install and Configure Fail2ban
Fail2ban monitors auth logs and bans IPs that repeatedly fail authentication:
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Create a local config to override defaults (avoiding changes to the package defaults):
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
Restart:
sudo systemctl restart fail2ban
Check status:
sudo fail2ban-client status
sudo fail2ban-client status sshd
7. Set Up Time Synchronization
Accurate time is critical for logs, certificates, and security protocols:
sudo apt install chrony -y
sudo systemctl enable chrony
sudo systemctl start chrony
Verify:
chronyc tracking
8. Harden Kernel Parameters (Optional but Recommended)
Add a few sysctl settings to improve network security:
sudo nano /etc/sysctl.d/99-hardening.conf
# Disable ICMP redirect acceptance
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# Enable TCP SYN cookies (prevent SYN flood attacks)
net.ipv4.tcp_syncookies = 1
# Hide kernel version from ICMP
net.ipv4.icmp_echo_ignore_all = 1
Apply:
sudo sysctl --system
9. Review Open Ports
Regularly check what’s listening:
# List all listening TCP ports
sudo ss -tlnp
# Check for unexpected services
sudo netstat -tlnp
Only services you explicitly installed should be listening. Shut down anything unexpected.
10. Set Up Logwatch for Monitoring
Logwatch summarizes daily log activity:
sudo apt install logwatch -y
Configure it to email you daily (requires a working mail setup):
sudo nano /etc/cron.daily/00logwatch
Add:
/usr/sbin/logwatch --output mail --mailto your@email.com --range today --detail high
Quick Reference
| Task | Command |
|---|---|
| Check SSH status | sudo systemctl status sshd |
| Check firewall | sudo ufw status verbose |
| Check fail2ban | sudo fail2ban-client status sshd |
| Check open ports | sudo ss -tlnp |
| Apply kernel hardening | sudo sysctl --system |
When You’re Done
After hardening, your VPS has:
- SSH key-only authentication
- Root login disabled
- Firewall allowing only HTTP/HTTPS/SSH
- Automatic security updates
- Brute-force protection via fail2ban
- Accurate time synchronization
- Hardened network parameters
This is the baseline for any production server. The specific services you run (nginx, Docker, Coolify, etc.) will have their own hardening requirements, but this foundation applies universally.