Tutorial, Ubuntu 24.04
UFW and fail2ban setup. A firewall that can’t lock you out.
Bots start guessing SSH passwords within minutes of a server going online. Here’s the firewall and the ban list that stop them, set up so a typo can’t lock you out.
24 hours before
00-hardening.conf
PermitRootLogin no PasswordAuthentication no KbdInteractiveAuthentication no AllowUsers deploy
After
0 password guesses
Bots still connect. Nothing left to guess.
The short answer
Allow SSH first, then enable UFW, then add fail2ban. Set UFW to deny incoming and allow outgoing, allow your SSH port (rate-limited with ufw limit), allow only the services you run, and arm a three-minute rollback timer before ufw enable. Then install fail2ban and enable its SSH jail in jail.local.
The builder below writes the UFW commands for your server in that safe order.
Most UFW guides tell you to run ufw enable, and some do it before allowing SSH, which cuts you off from your own server. Most fail2ban guides tell you to edit jail.conf, which the file itself says not to touch.
This one gets the order right. A rule builder for the services you run, a timer that undoes the firewall if you lose access, the Docker catch almost nobody mentions, and a fail2ban jail that survives updates.
In this guide you’ll learn
- A UFW rule builder for your services, in a safe order
- The rollback timer that makes a lockout impossible
- The Docker catch: published ports skip UFW
- fail2ban for SSH, in jail.local
- Checking and unbanning
Chapter 1
Build your UFW rules
Tick what your server runs. The builder writes the commands: defaults first, SSH next, your services, a rollback timer, and only then ufw enable.
Run these, in order
sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw limit 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo systemd-run --on-active=180 --unit=ufw-rollback /usr/sbin/ufw disable sudo ufw enable
Answer y when ufw warns about SSH. Then log in from a new window. If you can’t, wait three minutes: the timer turns the firewall off again. If you can:
sudo systemctl stop ufw-rollback.timer sudo ufw status verbose
Chapter 2
The Docker catch
This is the one that surprises people.
Docker writes its own firewall rules for published ports, and those rules are evaluated before UFW’s. So a container started with -p 8080:80 is reachable from the internet even when UFW says 8080 is closed.
- Publish to localhostHow to check: Use
-p 127.0.0.1:8080:80and put a reverse proxy such as Caddy in front; only the proxy’s 80 and 443 face the internet. - Or don’t publish at allHow to check: Containers on the same Docker network reach each other without published ports.
- Check from outsideHow to check: From your own PC, try the port: if
nc -vz your-server-ip 8080connects, it’s open, whatever UFW says.
Our Docker on a VPS tutorial sets this up from the start.
Chapter 3
Set up fail2ban for SSH
UFW decides which ports are open. fail2ban watches the login attempts on them and bans addresses that keep failing.
Usernames bots guessed most (none existed with a password)
admin411ubuntu342user206deploy183test148user197ftpuser70
7,110 more attempts went straight for root.
Install it
sudo apt update && sudo apt install -y fail2ban
Write your settings in jail.local
jail.confis replaced by package updates and says itself not to edit it. Your overrides go injail.local, which is read after it:sudo tee /etc/fail2ban/jail.local > /dev/null <<'EOF' [DEFAULT] bantime = 1h findtime = 10m maxretry = 5 ignoreip = 127.0.0.1/8 ::1 [sshd] enabled = true port = 22 EOF
Changed your SSH port? Put it on the
portline. Add your own fixed IP toignoreipso you can never ban yourself.Restart and check
sudo systemctl restart fail2ban sudo fail2ban-client status sshd
Chapter 4
Check, unban and keep it tidy
The commands you’ll actually use.
sudo ufw status numbered # list rules with numbers sudo ufw delete 4 # remove rule number 4 sudo fail2ban-client status sshd # who is banned right now sudo fail2ban-client set sshd unbanip 203.0.113.50
MythA firewall makes SSH keys unnecessary.
Port 22 still has to be open for you. Keys are what stop the guessing; our SSH hardening tutorial turns passwords off.
Mythfail2ban replaces the firewall.
fail2ban bans addresses that misbehave on open ports. UFW decides which ports are open at all. You want both.
Now it’s your move
A firewall that only opens what you use, a rate limit on SSH, and a ban list for the bots that keep trying. Set up in the right order, none of it can lock you out.
Deploy a Lite, paste the builder’s commands, and add the jail. The rest of the first hour is in our VPS security guide.