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"