Lesson 2 of 7 · 20m
ufw and fail2ban: The Perimeter in Two Commands
Deny everything, allow what you serve — plus the brute-force tarpit that quiets your auth logs.
Perimeter security on a single host is boring by design: close everything except what you serve, and slow down the bots that pound what's open.
ufw: default deny, explicit allow
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp # SSH — before enabling, or you lock yourself out
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable && sudo ufw status verboseThat's the whole firewall. Every service you add is one ufw allow — and a deliberate decision instead of an accident.
fail2ban: the tarpit
sudo apt install fail2ban
sudo systemctl enable --now fail2banThe default sshd jail bans IPs after a few bad password attempts. With password auth off it's mostly cosmetic — but it keeps your auth log readable, and on services that do take credentials (webmail, admin panels) it genuinely reduces pressure. Check fail2ban-client status sshd when tuning.
What the firewall can't do
ufw governs what's reachable, not what's safe: an open 443 serving a container with a 2019 CMS is a hole. The firewall's job is shrinking the surface; the service's job is being worth exposing.
::exercise(allow-ssh)
::lab(lock-the-door)
Field notes
- Docker bypasses ufw rules by default (it programs iptables directly) — published ports are reachable even with ufw deny. Bind to
127.0.0.1or accept the bypass knowingly. - IPv6 exists:
ufwhandles both, but a rule you think closes a service may leave it open on::— test both. ss -tulpnis the audit: what's actually listening vs what you think is listening.