Skip to content
Black FridayCode BLACK150: 150% on your first deposit of $100 or more, up to $500 bonus. New accounts, until 1 Dec, 00:00 UTC.Get the code
LiteKeep
Sign inDeploy a server

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.

  • 10 min read
  • 4 chapters
  • Updated

24 hours before

  • Failed passwords821
  • of which for root539
  • Unknown users183

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.

Your server

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.

  1. Publish to localhostHow to check: Use -p 127.0.0.1:8080:80 and put a reverse proxy such as Caddy in front; only the proxy’s 80 and 443 face the internet.
  2. Or don’t publish at allHow to check: Containers on the same Docker network reach each other without published ports.
  3. Check from outsideHow to check: From your own PC, try the port: if nc -vz your-server-ip 8080 connects, 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.

24 minfrom first boot to the first password guess
14,526failed password attempts in about 70 hours
209attempts an hour, on average
219different addresses doing the guessing

Usernames bots guessed most (none existed with a password)

  1. admin411
  2. ubuntu342
  3. user206
  4. deploy183
  5. test148
  6. user197
  7. ftpuser70

7,110 more attempts went straight for root.

Figure 1. What hit a brand-new LiteKeep server (Ubuntu 22.04, SSH on port 22) between 19 and 22 October 2026, read from its own logs. One server and one window: an example, not a global rate.
  1. Install it

    sudo apt update && sudo apt install -y fail2ban
  2. Write your settings in jail.local

    jail.conf is replaced by package updates and says itself not to edit it. Your overrides go in jail.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 port line. Add your own fixed IP to ignoreip so you can never ban yourself.

  3. 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.

Fact

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.

Fact

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.