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:
- Navigate to Firewalls in your DanubeData dashboard
- Click Create Firewall
- 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
- Attach the firewall to your VPS instance
- 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:
- Go to Firewalls β Select your firewall β Edit Rules
- Find your SSH rule (port 22 or custom)
- Set Source to your IP address (e.g., 203.0.113.45/32)
- Or set to CIDR range for office network (e.g., 203.0.113.0/24)
- 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):
- Log in to DanubeData dashboard
- Navigate to Firewalls
- Select your firewall and click Edit Rules
- Update SSH rule to allow your new IP address or temporarily allow 0.0.0.0/0
- Click Save - changes apply immediately
- SSH into your server from the new location
- 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:
- Update DanubeData firewall to temporarily allow SSH from 0.0.0.0/0
- SSH in and fix configuration
- Immediately restrict firewall to your IP again
- 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)
- Create your DanubeData account
- Deploy Ubuntu VPS (2-core, 4GB - $8.99/month)
- Add your SSH public key during setup (automatically injected)
- Create a firewall in the dashboard:
- Allow SSH from your IP only
- Allow HTTP/HTTPS from anywhere (if needed)
- Attach firewall to VPS instance
- SSH into your server with key-based auth (already configured)
- Deploy your application - firewall is active
Time to secure VPS: ~3 minutes (vs 30+ minutes for manual hardening)
Advanced Setup (Hybrid Security)
- Follow Quick Start above for managed firewall
- Additionally implement manual SSH hardening from this guide:
- Disable password auth (if not already disabled)
- Change SSH port
- Setup Fail2Ban
- Enable 2FA
- 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.