Combining SSH Hardening, Fail2ban, and UFW for a Secure Server

SSH hardening, Fail2ban, and a properly configured firewall work together as layered defense — each one closes a gap the others don’t fully cover on their own.

# Layer 1: UFW - default-deny firewall, only explicitly allowed ports open
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp    # or your custom SSH port
sudo ufw allow 80,443/tcp
sudo ufw enable

# Layer 2: SSH hardening - key-only auth, no root login
sudo sed -i 's/#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd

# Layer 3: Fail2ban - automatically bans repeated failed attempts
sudo apt install fail2ban
sudo systemctl enable --now fail2ban

Why All Three, Not Just One

UFW blocks unexpected ports entirely, but a legitimate open port (like SSH) still needs its own protection against credential attacks — that’s what SSH’s key-only authentication handles. Fail2ban then adds a further layer specifically against distributed or slow brute-force attempts that might otherwise go unnoticed even with strong authentication in place. Each layer covers a gap the others genuinely don’t.

Verifying It’s Actually Working

sudo ufw status verbose
sudo fail2ban-client status sshd
sudo sshd -T | grep -E "permitrootlogin|passwordauthentication"