BlogSecuritySSH Hardening Checklist: Secure Your VPS in 10 Steps

SSH Hardening Checklist: Secure Your VPS in 10 Steps

Adrian Silaghi
Adrian Silaghi
December 10, 2025
12 min read
32 views
#ssh #security #vps #linux #hardening #fail2ban

SSH is the front door to your server. A poorly configured SSH setup is an open invitation to attackers. This checklist walks you through 10 essential steps to lock down SSH access and secure your VPS.

Why SSH Security Matters

Common Attack Vectors

  • Brute force attacks: Automated tools try thousands of password combinations
  • Default credentials: Attackers try common username/password pairs
  • Exposed root login: Direct root access gives full server control
  • Outdated SSH versions: Known vulnerabilities in old SSH software
  • Weak passwords: Easy-to-guess passwords compromised in minutes

Real Statistics

  • Average VPS receives hundreds of SSH login attempts per day
  • Bots scan for open port 22 within minutes of server deployment
  • Compromised servers used for crypto mining, spam, DDoS attacks
  • Security breach cleanup costs: $100-10,000+ in time and data loss

Good news: Following this checklist reduces your attack surface by 99%.

Two Approaches to VPS Security

You have two options for securing your VPS:

πŸš€ Option 1: DanubeData Managed Security (Easiest)

DanubeData VPS instances come with infrastructure-level security features:

  • Managed Firewalls: Configure via dashboard, enforced at Kubernetes NetworkPolicy level
  • SSH Key Injection: Your SSH keys added automatically via cloud-init
  • Automated Backups: Daily snapshots for quick recovery

Best for: Users who want enterprise security without manual configuration.

πŸ”§ Option 2: Manual Hardening (Full Control)

Follow the 10-step checklist below to configure everything manually:

  • Complete control: Configure every security setting yourself
  • Provider agnostic: Works on any VPS provider (AWS, DigitalOcean, Linode, etc.)
  • Learning opportunity: Understand security fundamentals

Best for: Security professionals, educational purposes, or non-DanubeData VPS providers.

πŸ’‘ Recommended: Hybrid Approach

Use DanubeData's managed firewall for network-level protection, plus manual SSH hardening for defense in depth.


The SSH Hardening Checklist

βœ… Step 1: Create a Non-Root User with Sudo Access

Why: Never use root for daily operations. If credentials leak, attackers get limited access.

# Log in as root (first time only)
ssh root@your-vps-ip

# Create new user
adduser deployer

# Add to sudo group
usermod -aG sudo deployer

# Test sudo access
su - deployer
sudo apt update

# Verify
sudo whoami  # Should output: root

⚠️ Important: Don't log out as root yet. Keep the session open until Step 3 is complete and tested.

βœ… Step 2: Setup SSH Key Authentication

Why: SSH keys are virtually uncrackable. Passwords can be brute-forced.

On Your Local Machine (Mac/Linux):

# Generate SSH key pair (if you don't have one)
ssh-keygen -t ed25519 -C "your-email@example.com"

# Press Enter for default location (~/.ssh/id_ed25519)
# Set a strong passphrase (optional but recommended)

# Copy public key to VPS
ssh-copy-id deployer@your-vps-ip

On Windows (PowerShell):

# Generate key
ssh-keygen -t ed25519 -C "your-email@example.com"

# Manually copy key to server
type $env:USERPROFILE.sshid_ed25519.pub | ssh deployer@your-vps-ip "cat >> ~/.ssh/authorized_keys"

Verify Key Authentication Works:

# Test login without password
ssh deployer@your-vps-ip

# Should log in without asking for password

βœ… Step 3: Disable Password Authentication

Why: Eliminates brute force attacks completely. No password = nothing to crack.

# Edit SSH config
sudo nano /etc/ssh/sshd_config

Find and modify these lines:

# Disable password authentication
PasswordAuthentication no

# Disable challenge-response authentication
ChallengeResponseAuthentication no

# Disable PAM authentication
UsePAM no

# Ensure public key authentication is enabled
PubkeyAuthentication yes

Test configuration and restart SSH:

# Test config for syntax errors
sudo sshd -t

# If no errors, restart SSH
sudo systemctl restart sshd

🚨 Critical: Keep your root session open. Open a NEW terminal and test SSH login as deployer. Only close root session after confirming you can log in.

βœ… Step 4: Disable Root Login

Why: Attackers always target root. Disabling it forces them to guess your username too.

sudo nano /etc/ssh/sshd_config

Find and set:

PermitRootLogin no

Restart SSH:

sudo systemctl restart sshd

βœ… Step 5: Change Default SSH Port (Optional but Recommended)

Why: Automated bots scan port 22. Moving to a non-standard port eliminates 99% of attack attempts.

sudo nano /etc/ssh/sshd_config

Change port (choose 1024-65535):

# Find this line:
# Port 22

# Change to custom port:
Port 2222

Update firewall (if using UFW):

# Allow new SSH port
sudo ufw allow 2222/tcp

# IMPORTANT: Test new port works before closing port 22
ssh -p 2222 deployer@your-vps-ip

# After confirming new port works:
sudo ufw delete allow 22/tcp

# Restart SSH
sudo systemctl restart sshd

Update your SSH config for convenience:

# On your local machine
nano ~/.ssh/config

Add:

Host myvps
    HostName your-vps-ip
    Port 2222
    User deployer
    IdentityFile ~/.ssh/id_ed25519

# Now you can connect with: ssh myvps

βœ… Step 6: Install and Configure Fail2Ban

Why: Automatically bans IPs after failed login attempts. Stops brute force attacks in their tracks.

# Install Fail2Ban
sudo apt update
sudo apt install fail2ban -y

# Create local configuration
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

Find the [sshd] section and configure:

[sshd]
enabled = true
port = 2222  # Match your SSH port
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

Settings explained:

  • maxretry: Failed attempts before ban (3 = strict)
  • bantime: Ban duration in seconds (3600 = 1 hour)
  • findtime: Time window for failed attempts (600 = 10 minutes)

Start Fail2Ban:

# Enable and start
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# Check status
sudo fail2ban-client status sshd

βœ… Step 7: Setup Firewall Protection

Why: Only expose necessary ports. Close everything else.

Option 1: DanubeData Managed Firewall (Recommended)

DanubeData VPS instances include integrated firewall management through the dashboard:

  1. Navigate to Firewalls in your DanubeData dashboard
  2. Click Create Firewall
  3. Add inbound rules for necessary services:
    • SSH: Port 22 (or your custom port) from your IP
    • HTTP: Port 80 from 0.0.0.0/0
    • HTTPS: Port 443 from 0.0.0.0/0
  4. Attach the firewall to your VPS instance
  5. Rules are applied automatically via Kubernetes NetworkPolicies

Benefits of DanubeData Firewall:

  • βœ… Managed at infrastructure level (more secure than host-based)
  • βœ… No software to install or configure on VPS
  • βœ… Changes applied instantly without SSH access
  • βœ… Reusable across multiple VPS instances
  • βœ… Version controlled and auditable
  • βœ… Survives VPS rebuilds automatically

Option 2: Manual UFW Configuration

For full control or when using other providers:

# Install UFW (usually pre-installed on Ubuntu)
sudo apt install ufw

# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH (use your custom port)
sudo ufw allow 2222/tcp

# Allow HTTP/HTTPS if running web server
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable firewall
sudo ufw enable

# Check status
sudo ufw status verbose

Expected output:

Status: active

To                         Action      From
--                         ------      ----
2222/tcp                   ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere

πŸ’‘ Pro Tip: On DanubeData, you can use both managed firewalls (infrastructure-level) AND UFW (host-level) for defense in depth. The managed firewall blocks traffic before it reaches your VPS.

βœ… Step 8: Limit SSH Access by IP (Optional, High Security)

Why: If you have a static IP, only allow SSH from your location.

Option 1: DanubeData Managed Firewall

Edit your firewall in the dashboard:

  1. Go to Firewalls β†’ Select your firewall β†’ Edit Rules
  2. Find your SSH rule (port 22 or custom)
  3. Set Source to your IP address (e.g., 203.0.113.45/32)
  4. Or set to CIDR range for office network (e.g., 203.0.113.0/24)
  5. Click Save - changes apply immediately

Benefits: Can update from dashboard even if locked out of SSH.

Option 2: Manual UFW Configuration

# Allow SSH only from your IP
sudo ufw delete allow 2222/tcp
sudo ufw allow from YOUR_IP_ADDRESS to any port 2222

# Example:
sudo ufw allow from 203.0.113.45 to any port 2222

# Check rules
sudo ufw status numbered

Caution: Only use if you have a static IP. Dynamic IPs will lock you out.

Alternative: Allow IP Range

# Allow entire subnet (e.g., your office network)
sudo ufw allow from 203.0.113.0/24 to any port 2222

βœ… Step 9: Configure SSH Idle Timeout

Why: Auto-disconnect inactive sessions to prevent hijacking.

sudo nano /etc/ssh/sshd_config

Add or modify:

# Disconnect after 5 minutes of inactivity
ClientAliveInterval 300
ClientAliveCountMax 0

# Alternative: Warn before disconnect (3 pings of 100 seconds)
ClientAliveInterval 100
ClientAliveCountMax 3

Restart SSH:

sudo systemctl restart sshd

βœ… Step 10: Enable Two-Factor Authentication (2FA)

Why: Even if your SSH key is compromised, attackers need your phone.

# Install Google Authenticator
sudo apt install libpam-google-authenticator -y

# Run setup as your user (not root)
google-authenticator

Answer the questions:

  • Time-based tokens? Yes
  • Update ~/.google_authenticator? Yes
  • Disallow multiple uses? Yes
  • Increase time window? No (unless you have clock sync issues)
  • Enable rate-limiting? Yes

Scan the QR code with Google Authenticator app on your phone.

Configure PAM:

sudo nano /etc/pam.d/sshd

Add at the top:

auth required pam_google_authenticator.so

Configure SSH:

sudo nano /etc/ssh/sshd_config

Modify:

ChallengeResponseAuthentication yes
UsePAM yes
AuthenticationMethods publickey,keyboard-interactive

Restart SSH:

sudo systemctl restart sshd

Test login - you'll need both SSH key AND 2FA code.

Verify Your Security Setup

Security Audit Checklist

# Check SSH config
sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin|port|pubkeyauthentication'

# Check firewall status
sudo ufw status verbose

# Check Fail2Ban status
sudo fail2ban-client status sshd

# View recent failed login attempts
sudo grep "Failed password" /var/log/auth.log | tail -20

# View banned IPs
sudo fail2ban-client status sshd

# Check who's logged in
who

# Check SSH active connections
ss -tnp | grep :2222

Monitoring and Maintenance

Daily Monitoring Commands

# Check failed login attempts
sudo tail -f /var/log/auth.log | grep "Failed"

# List currently banned IPs
sudo fail2ban-client status sshd

# Unban an IP (if you locked yourself out)
sudo fail2ban-client set sshd unbanip YOUR_IP

# View successful logins
last -a | head -20

Setup Login Alerts (Optional)

Get email notification on every SSH login:

# Create alert script
sudo nano /etc/ssh/login-notify.sh

Add:

#!/bin/bash
echo "SSH Login Alert: $(date)" | mail -s "SSH Login on $(hostname)" your-email@example.com
# Make executable
sudo chmod +x /etc/ssh/login-notify.sh

# Add to .bashrc
echo "/etc/ssh/login-notify.sh" >> ~/.bashrc

Emergency Access Recovery

If You Lock Yourself Out

Option 1: Update Managed Firewall (Recommended)

If you're blocked by firewall rules (e.g., your IP changed):

  1. Log in to DanubeData dashboard
  2. Navigate to Firewalls
  3. Select your firewall and click Edit Rules
  4. Update SSH rule to allow your new IP address or temporarily allow 0.0.0.0/0
  5. Click Save - changes apply immediately
  6. SSH into your server from the new location
  7. After logging in, update firewall to restrict to your new IP again

Benefits:

  • No SSH access required - update from dashboard
  • Changes apply instantly via Kubernetes NetworkPolicies
  • Can be done from anywhere (phone, laptop, etc.)
  • No server reboot needed

Option 2: Keep a Backup SSH Session Open

Before making risky changes:

# Open a second SSH session in another terminal
ssh deployer@your-vps-ip

# Test changes in first session
# If locked out, use second session to fix

# Only close backup session after confirming changes work

Option 3: Temporarily Allow All IPs (Emergency Only)

If completely locked out and need immediate access:

  1. Update DanubeData firewall to temporarily allow SSH from 0.0.0.0/0
  2. SSH in and fix configuration
  3. Immediately restrict firewall to your IP again
  4. Monitor auth logs: sudo tail -f /var/log/auth.log

⚠️ Warning: Only leave SSH open to 0.0.0.0/0 for a few minutes. You'll see brute force attempts within seconds.

Advanced Security (Beyond SSH)

Additional Hardening Steps

  • Setup automatic security updates: sudo apt install unattended-upgrades
  • Install intrusion detection: AIDE, OSSEC, or Wazuh
  • Enable AppArmor/SELinux: Mandatory access control
  • Regular security audits: Lynis (sudo lynis audit system)
  • Log aggregation: Send logs to external service (Papertrail, Logtail)

Run Security Audit with Lynis

# Install Lynis
sudo apt install lynis

# Run full system audit
sudo lynis audit system

# Review results
cat /var/log/lynis.log

Complete SSH Config Reference

Your final /etc/ssh/sshd_config should include:

# Network
Port 2222
AddressFamily inet
ListenAddress 0.0.0.0

# Authentication
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication yes  # For 2FA
UsePAM yes
AuthenticationMethods publickey,keyboard-interactive

# Security
StrictModes yes
MaxAuthTries 3
MaxSessions 2
LoginGraceTime 30

# Timeouts
ClientAliveInterval 300
ClientAliveCountMax 0

# Disable dangerous features
X11Forwarding no
PermitUserEnvironment no
AllowAgentForwarding no
AllowTcpForwarding no
PermitTunnel no

# Logging
SyslogFacility AUTH
LogLevel VERBOSE

# Allow only specific users (optional)
AllowUsers deployer admin

# Protocol
Protocol 2

Quick Reference: Security Levels

Level Steps Required Security
πŸ”΄ Minimal Steps 1-4 Basic - blocks 90% of attacks
🟑 Recommended Steps 1-7 Good - blocks 99% of attacks
🟒 High Security Steps 1-10 Excellent - enterprise-grade

Common Mistakes to Avoid

  • ❌ Disabling password auth before testing SSH keys β†’ Lock yourself out
  • ❌ Changing SSH port without updating firewall β†’ Can't connect
  • ❌ Not keeping root session open while testing β†’ Emergency recovery needed
  • ❌ Using weak SSH key passphrases β†’ Defeats the purpose
  • ❌ Forgetting to restart sshd after config changes β†’ Changes not applied
  • ❌ Setting Fail2Ban maxretry too low β†’ Lock yourself out on typos
  • ❌ Allowing SSH from 0.0.0.0/0 when you have static IP β†’ Unnecessary exposure

Testing Your Security

SSH Configuration Test

# Verify SSH config syntax
sudo sshd -t

# Check what settings are active
sudo sshd -T

# Test connection (from another machine)
ssh -v deployer@your-vps-ip -p 2222

# Verify password login is disabled
ssh -o PreferredAuthentications=password deployer@your-vps-ip
# Should fail with "Permission denied"

Port Scanning Test

# From your local machine (requires nmap)
nmap -p 1-65535 your-vps-ip

# Should only show your allowed ports

DanubeData Security Features

All DanubeData VPS instances include enterprise-grade security:

Infrastructure-Level Security

  • βœ… Managed Firewalls - Network-level firewall rules via Kubernetes NetworkPolicies
    • Create reusable firewall configurations
    • Attach/detach firewalls to multiple VPS instances
    • Changes apply instantly without SSH access
    • Inbound and outbound rule support
    • IP whitelisting with CIDR notation
  • βœ… DDoS Protection - Built-in at network level via Hetzner
  • βœ… Isolated Networking - Each VPS runs in isolated network namespace
  • βœ… Node-Level Security - VPS nodes hardened with taints and tolerations

Operational Security

  • βœ… Automated Backups - Daily snapshots with Longhorn (7-day retention)
  • βœ… SSH Key Injection - Cloud-init adds your SSH keys automatically
  • βœ… European Data Center - GDPR-compliant infrastructure in Germany
  • βœ… Security Updates - Ubuntu LTS images patched regularly
  • βœ… Audit Logs - All firewall changes tracked and versioned

How DanubeData Firewalls Work

DanubeData uses Kubernetes NetworkPolicies to enforce firewall rules:

# Example: Firewall blocks traffic at infrastructure layer
Internet β†’ Hetzner DDoS Protection β†’ Kubernetes NetworkPolicy β†’ VPS

# If you also enable UFW:
Internet β†’ Hetzner DDoS β†’ NetworkPolicy β†’ UFW β†’ VPS (Defense in depth)

Advantages over traditional host-based firewalls:

  • Rules enforced even if VPS is compromised
  • No CPU/memory overhead on VPS itself
  • Centralized management across multiple VPS instances
  • Can modify rules without SSH access (via dashboard)
  • Automatically reapplied if VPS is rebuilt

Summary Checklist

Print this and check off as you complete:

  • ☐ Create non-root user with sudo access
  • ☐ Setup SSH key authentication
  • ☐ Disable password authentication
  • ☐ Disable root login
  • ☐ Change SSH to non-standard port
  • ☐ Install and configure Fail2Ban
  • ☐ Setup firewall (managed or UFW)
  • ☐ Limit SSH access by IP (optional)
  • ☐ Configure SSH idle timeout
  • ☐ Enable two-factor authentication (optional)
  • ☐ Test all changes before closing root session
  • ☐ Setup monitoring and alerts

Get Started with Secure Hosting

Deploy a hardened VPS with DanubeData in under 5 minutes:

Quick Start (Managed Security)

  1. Create your DanubeData account
  2. Deploy Ubuntu VPS (2-core, 4GB - $8.99/month)
  3. Add your SSH public key during setup (automatically injected)
  4. Create a firewall in the dashboard:
    • Allow SSH from your IP only
    • Allow HTTP/HTTPS from anywhere (if needed)
  5. Attach firewall to VPS instance
  6. SSH into your server with key-based auth (already configured)
  7. Deploy your application - firewall is active

Time to secure VPS: ~3 minutes (vs 30+ minutes for manual hardening)

Advanced Setup (Hybrid Security)

  1. Follow Quick Start above for managed firewall
  2. Additionally implement manual SSH hardening from this guide:
    • Disable password auth (if not already disabled)
    • Change SSH port
    • Setup Fail2Ban
    • Enable 2FA
  3. Result: Defense in depth with infrastructure + host-level security

Why Choose DanubeData for Secure VPS Hosting?

Security Feature DanubeData DigitalOcean AWS Lightsail
Managed Firewall βœ“ Included βœ“ Cloud Firewalls Manual only
SSH Key Auto-Injection βœ“ Cloud-init βœ“ Supported βœ“ Supported
Automated Backups βœ“ Daily (included) $1.60/mo extra βœ“ Snapshots
DDoS Protection βœ“ Hetzner Network Basic included βœ“ AWS Shield
EU Data Residency βœ“ Germany Multiple regions Multiple regions
Price (2-core, 4GB) $8.99/mo $24/mo $20/mo

Questions about VPS security? Contact our team or check our security documentation.

Share this article

Ready to Get Started?

Deploy your infrastructure in minutes with DanubeData's managed services.