Initial Hardening Checklist for Fresh VPS Servers on Hetzner & OVH
The moment your cloud hosting provider (Hetzner Cloud, OVH, DigitalOcean, or AWS) assigns a public IPv4 address, automated port scanners and brute-force bots begin probing port 22.
Inspect /var/log/auth.log just fifteen minutes after boot on a default installation, and you will find hundreds of failed login attempts targeting root with common dictionaries (admin, 123456, ubuntu).
Applying a rigorous hardening checklist within your first ten minutes is the difference between a resilient production server and a compromised node exploited for cryptomining or DDoS amplification.
Here is the step-by-step technical checklist for Ubuntu and Debian Linux servers.
1. System Updates and Dedicated Non-Root User
Never perform daily operations as root. Begin by updating system packages and installing baseline security tools:
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl ufw fail2ban unattended-upgrades
Create a dedicated administrative user with sudo permissions:
# Create user (replace 'devops' with your desired handle)
adduser devops
# Add user to sudo group
usermod -aG sudo devops
Copy your local public SSH key to the new user before proceeding:
# On your local terminal:
ssh-copy-id devops@YOUR_VPS_PUBLIC_IP
Verify you can log in without password prompts (ssh devops@YOUR_VPS_PUBLIC_IP) before disabling password access.
2. Strict SSH Daemon Hardening (sshd_config)
Over 95% of automated attacks target SSH passwords. Disabling passwords completely stops these vectors.
Open the SSH daemon configuration:
sudo nano /etc/ssh/sshd_config
Set the following parameters:
# Disable direct root login
PermitRootLogin no
# Enforce cryptographic public key authentication
PubkeyAuthentication yes
# Completely disable password authentication
PasswordAuthentication no
ChallengeResponseAuthentication no
# Limit auth attempts per connection
MaxAuthTries 3
# Disconnect idle sessions
ClientAliveInterval 300
ClientAliveCountMax 2
Validate syntax before reloading:
sudo sshd -t
If no errors are emitted, restart SSH:
sudo systemctl restart ssh
(Note: Keep your existing SSH session active in one window while testing a new connection in another).
3. Configure the UFW Firewall
Unspecified ports must be unreachable. The rule must be default deny incoming:
# Default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH before enabling!
sudo ufw allow ssh
# Allow HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable firewall
sudo ufw enable
Review your rules with sudo ufw status verbose. If running Docker on this server, ensure you review our guide on how to fix the Docker UFW bypass on Ubuntu.
4. Enable Fail2ban with Progressive Ban Times
Fail2ban monitors logs for repeated failed logins and temporarily bans offending IPs:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Configure the SSH jail:
[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 3
findtime = 10m
bantime = 1h
Restart and check status:
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
5. Enable Unattended Security Updates
Most breaches exploit vulnerabilities patched months prior. Enable unattended-upgrades so security advisories are applied automatically:
sudo dpkg-reconfigure --priority=low unattended-upgrades
Checklist Summary
| Check | Target Configuration | Verification Command |
|---|---|---|
| Root Login | Disabled (no) |
grep "^PermitRootLogin" /etc/ssh/sshd_config |
| Password Auth | Disabled (no) |
grep "^PasswordAuthentication" /etc/ssh/sshd_config |
| Firewall | Active (default: deny) |
sudo ufw status verbose |
| Fail2ban | Active on SSH | sudo fail2ban-client ping |
| Auto Upgrades | Active | systemctl is-active unattended-upgrades |
Continuous Automated Auditing with FerroSentry
Applying this checklist once is good; keeping it enforced over time as dependencies and containers evolve is better.
With FerroSentry, our open source Rust audit agent:
- 9 internal security modules run read-only continuous audits.
- Consumes under 15 MB RAM and <0.2% CPU.
- Instantly alerts if a Docker container bypasses UFW or password authentication is accidentally re-enabled.
Audit your VPS in 30 seconds with SecuryBlack's free tier.