Skip to main content

Fail2Ban Magic: Keeping Your Django Castle Safe 🏰🐾

Using fail2ban on VPS to secure your linux sever.

Updated 4 min readMarkdown
Fail2Ban Magic: Keeping Your Django Castle Safe 🏰🐾

Imagine your Django server is a cozy castle. Brave knights (your users) come and go, but naughty robots (bad bots) sometimes knock repeatedly on secret doors (login pages) trying to sneak in. We need Fail2Ban, a friendly guard dog, to watch the castle logs and chase away any robot that knocks too many times!


1. What Is Fail2Ban?

  • Guard Dog: Monitors log files like a watchful puppy.

  • Jails: Special zones around each door (service) where the guard listens.

  • Filters: Magic spells (regular expressions) that spot naughty knocks (bad actions).

  • Actions: When a robot misbehaves too much, the guard slams the door shut by adding a firewall rule.


2. Why Use Fail2Ban with Django?

  1. Protect the Admin Tower
    The /admin/ page is a treasure room. Don’t let robots guess passwords!

  2. Guard the Login Gate
    Your API login endpoint (/auth/login/) needs extra eyes.

  3. Stop Crawler Floods
    Bots triggering hundreds of 404 pages can overwhelm the castle.

  4. Layered Security
    Compliments your Django settings.py security (SSL redirect, HSTS, X-Frame-Options).


3. Setting Up Fail2Ban Step-by-Step

Step 3.1: Install Your Guard

sudo apt update
sudo apt install -y ufw fail2ban
  • UFW: The castle’s drawbridge controller (firewall).

  • Fail2Ban: The guard dog watching your logs.

Step 3.2: Configure the Drawbridge (UFW)

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH            # Let knights in via SSH
sudo ufw allow 'Nginx Full'       # Let visitors reach your website (HTTP/HTTPS)
sudo ufw enable

Step 3.3: Create the Jail Configuration

Create /etc/fail2ban/jail.local and add:

[DEFAULT]
bantime  = 3600        # Ban duration: 1 hour
findtime = 600         # Look back: 10 minutes
maxretry = 5           # After 5 bad tries, ban

[sshd]
enabled = true
port    = ssh
filter  = sshd
logpath = /var/log/auth.log

[django-login]
enabled  = true
port     = http,https
filter   = django-login
logpath  = /var/log/nginx/access.log
  • bantime: How long the misbehaver is kicked out.

  • findtime: Time window to count failures.

  • maxretry: Number of strikes before the ban.

Step 3.4: Write Your Magic Spell (Filter)

Create /etc/fail2ban/filter.d/django-login.conf:

[Definition]
# Spot HTTP 401 responses on /auth/login/
failregex = ^<HOST> -.*POST /auth/login/.*" 401
ignoreregex =

This tells Fail2Ban: “Whenever you see a 401 Unauthorized on a login POST, count it!”

Step 3.5: Start the Guard Dog

sudo systemctl restart fail2ban

4. Testing Your Guard

  1. Check All Jails

    sudo fail2ban-client status
    
  2. Inspect the Django-Login Jail

    sudo fail2ban-client status django-login
    
  3. Simulate Robot Knocks

    for i in {1..6}; do
      curl -s -o /dev/null -w "%{http_code}" \
        -X POST https://your-domain.com/auth/login/ \
        -H "Content-Type: application/json" \
        -d '{"username":"bad","password":"bad"}'
    done
    

    After 5 “bad” tries, your IP should appear in the banned list!


5. Extra Security Tips

  • Protect Your Logs: Only root can edit /var/log/* so robots can’t erase evidence.

  • Combine with Django Security: In settings.py, enable:

    • SECURE_SSL_REDIRECT = True

    • HSTS (SECURE_HSTS_SECONDS)

    • X_FRAME_OPTIONS = "DENY"

  • Add More Jails:

    • nginx-http-auth (blocks repeated 401 basic-auth failures)

    • nginx-404 (blocks too many broken-page hits)

    • nginx-limit-req (stops traffic floods)

  • Tweak Thresholds: Adjust bantime, findtime, maxretry based on real traffic.

  • Email Alerts: Use action_mwl to notify you on each ban.


6. You Did It!

🎉 You now have a trusty Fail2Ban guard watching your Django castle. No more pesky robots breaking in! Keep learning, keep coding, and enjoy your safe server.


ox

Tired of doing all this by hand? ox deploys your repo to your own server for you. No Docker, no config maze. Try deploywithox.com

About the author

  • Hi, I’m a self-taught backend developer with 3+ years of experience, currently working at a tech startup based in The Bahamas. I mostly work with Python and Django, building APIs, designing database models, and improving performance when needed. I enjoy learning new tools and technologies as projects require.