SecuryBlack LogoSecuryBlack
Blog/Security

Initial Hardening Checklist for Fresh VPS Servers on Hetzner & OVH

·10 min read
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.