Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Ubuntu Fail2Ban Configuration Guide

By Kokil Thapa | Last reviewed: September 2026

Brute-force attacks against SSH and web login forms are routine on any public VPS. This Ubuntu Fail2Ban configuration guide walks you through installing Fail2Ban on Ubuntu 22.04 or 24.04, enabling the right jails, and tuning ban rules without locking yourself out. I run Fail2Ban alongside UFW on every production Ubuntu web server I maintain, including sister sites deployed with Deployer 7 and GitLab CI. Fail2Ban reads log files, counts failed attempts, and tells the firewall to block offending IPs for a set period.

What is Fail2Ban and how does it protect an Ubuntu server?

Fail2Ban is a log-parsing daemon. It watches authentication failures in system and application logs. When an IP crosses your threshold inside a time window, Fail2Ban adds a firewall rule. The block is temporary by default. That stops scripted attacks without permanent blacklists.

On Ubuntu web stacks, Fail2Ban sits between your services and Linux server administration tasks like firewall tuning. It does not replace UFW or iptables-nft. It automates reactions that you would otherwise script by hand.

Fail2Ban Protection FlowSSH Logs/var/log/auth.logWeb LogsNginx / ApacheApp LogsLaravel / WPFail2BanFilter + Jailfailregex matchUFW / nftDROP ruleTemporary banAttacker IP blocked after maxretry threshold
Ubuntu Fail2Ban configuration guide — logs flow into filters, jails trigger firewall bans

The core pieces are filters, jails, and actions. A filter defines regex patterns that match failed logins. A jail binds a filter to a log path, retry limits, and ban duration. An action executes the firewall command when a ban fires. Ubuntu packages ship sensible defaults for SSH. Web and CMS jails need explicit paths on your stack.

How do you install Fail2Ban on Ubuntu 22.04 or 24.04?

Install from the official Ubuntu repositories. Do not edit jail.conf directly. Package upgrades overwrite it. Always override settings in jail.local or drop files under jail.d/.

Install and enable the service

sudo apt update
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban

Confirm the daemon is active before you tune jails. A stopped Fail2Ban service gives a false sense of security. Your Ubuntu server setup checklist should include this step right after UFW and SSH key auth.

Create your local jail configuration

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

Set global defaults once at the top of [DEFAULT]. Per-jail sections inherit these values unless overridden.

[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
banaction = ufw
backend = systemd
ignoreip = 127.0.0.1/8 ::1 YOUR_OFFICE_IP

Replace YOUR_OFFICE_IP with a trusted address. I always whitelist my deploy runner and home IP. A typo here can lock you out during testing. Keep console access through your VPS provider as a backup.

Which Fail2Ban jails should you enable for SSH and web apps?

Enable the smallest set that covers real attack surfaces. SSH, HTTP auth, and CMS login endpoints cover most Laravel, WordPress, and Magento hosts I maintain. Extra jails add log parsing load with little gain on a quiet site.

Which Jails to EnablePublic Ubuntu VPS?Enable sshd jailWeb server running?Nginx jailshttp-auth, botsearchApache jailsauth, badbotsAdd CMS jails: wordpress, recidive
Jail selection for an Ubuntu Fail2Ban configuration guide — start with SSH, then match your web stack

SSH jail (always enable)

[sshd]
enabled  = true
port     = ssh
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 3
bantime  = 24h

Pair this with key-only SSH auth from our SSH hardening guide. Password auth should be disabled. Fail2Ban then catches leftover brute-force noise and misconfigured clients.

Nginx jails

[nginx-http-auth]
enabled  = true
port     = http,https
filter   = nginx-http-auth
logpath  = /var/log/nginx/error.log
maxretry = 5

[nginx-botsearch]
enabled  = true
port     = http,https
filter   = nginx-botsearch
logpath  = /var/log/nginx/access.log
maxretry = 2
bantime  = 24h

On Laravel deployments behind Nginx, also watch /var/log/nginx/access.log for probing paths like /.env or /wp-login.php. Custom filters help here. See our Laravel on Ubuntu with Nginx deployment notes for log locations.

Apache jails

[apache-auth]
enabled  = true
port     = http,https
filter   = apache-auth
logpath  = /var/log/apache2/error.log

[apache-badbots]
enabled  = true
port     = http,https
filter   = apache-badbots
logpath  = /var/log/apache2/access.log

Most of my Ubuntu 22.04 stacks use Apache with PHP-FPM for legacy PHP apps. The error log path must match your virtual host config. Wrong paths mean silent jails that never ban anyone.

WordPress and recidive jails

[wordpress]
enabled  = true
port     = http,https
filter   = wordpress
logpath  = /var/log/auth.log
          /var/log/nginx/access.log
maxretry = 3

[recidive]
enabled  = true
filter   = recidive
logpath  = /var/log/fail2ban.log
bantime  = 1w
findtime = 1d
maxretry = 3

The recidive jail bans repeat offenders for a week. It reads Fail2Ban's own log. That catches IPs that rotate through multiple jails. For WordPress-heavy hosts, also read our Fail2Ban configuration for PHP sites article.

How do you write a custom Fail2Ban filter for Laravel or WordPress?

Stock filters miss framework-specific login routes. A custom filter is a small INI file under /etc/fail2ban/filter.d/. You define failregex lines that match your log format.

Example: Laravel failed login filter

First, ensure Laravel logs failed auth attempts. The default single channel often writes to storage/logs/laravel.log. Log a consistent message from your auth controller or use Laravel's built-in lockout events.

sudo nano /etc/fail2ban/filter.d/laravel-auth.conf
[Definition]
failregex = ^.*local\.(ERROR|WARNING): .*Failed login attempt.*<HOST>.*$
            ^.*Failed login for .* from <HOST>.*$
ignoreregex =

Test the regex before enabling the jail:

sudo fail2ban-regex /var/www/app/storage/logs/laravel.log /etc/fail2ban/filter.d/laravel-auth.conf

The output shows matched and missed lines. Adjust patterns until real failures hit and legitimate traffic misses. Then create the jail:

sudo nano /etc/fail2ban/jail.d/laravel-auth.local
[laravel-auth]
enabled  = true
filter   = laravel-auth
logpath  = /var/www/app/shared/storage/logs/laravel.log
port     = http,https
maxretry = 5
findtime = 10m
bantime  = 1h

Use your actual deploy path. On Deployer 7 releases, point logpath at the shared storage symlink target. A stale path under an old release folder is a common post-deploy mistake I've seen on sister legal-tech sites like Notary Kathmandu.

Reload after every config change

sudo fail2ban-client reload
sudo fail2ban-client status
sudo fail2ban-client status sshd

Never restart Fail2Ban during an active ban test from your own IP. Use ignoreip first. The official Fail2Ban 0.11 manual documents filter syntax and jail options in detail.

What are the best ban times and retry limits for production servers?

Defaults are a starting point, not a final policy. Aggressive bans reduce noise but can block shared NAT users. Lenient settings waste CPU parsing logs that never result in blocks.

SettingDev / StagingProduction SSHProduction Web
maxretry1035
findtime10m10m10m
bantime10m24h1h
recidive bantimeoff1w1w

For high-traffic eCommerce hosts, longer web bantime values cut repeated scanner traffic. Pair tuning with PHP-FPM configuration for high-traffic sites so log volume stays manageable. Fail2Ban is not a DDoS tool. Volume-based attacks need CDN or upstream filtering. Our Fail2Ban vs Cloudflare comparison explains the split clearly.

UFW Alone vs UFW + Fail2BanUFW OnlyStatic port rulesManual IP blocksNo log analysisBrute force continuesuntil you reactUFW + Fail2BanAuto temp bansLog-driven rulesRecidive escalationBlocks repeatattackers fast
Ubuntu Fail2Ban configuration guide — UFW handles ports, Fail2Ban reacts to abuse patterns

I treat Fail2Ban as one layer in a wider hardening plan. Read our Ubuntu security hardening guide and server hardening for Ubuntu web servers for the full stack. That includes automatic security updates, ModSecurity where appropriate, and rate limits at the reverse proxy.

How do you test, monitor, and troubleshoot Fail2Ban on Ubuntu?

Configuration without verification is guesswork. Run structured tests after every jail change. Monitor ban counts weekly on production boxes.

Verify jails are running

sudo fail2ban-client status
sudo fail2ban-client status nginx-http-auth
sudo fail2ban-client get sshd bantime
sudo fail2ban-client get sshd maxretry

Each enabled jail should appear in the status list. Zero "currently banned" is normal on a quiet server. Zero "total banned" over weeks may mean a broken log path.

Simulate a ban safely

  1. Add your test IP to ignoreip if needed, or use a disposable VPS as the attacker.
  2. From the test machine, run ssh wronguser@your-server three times with bad passwords.
  3. On the server, run sudo fail2ban-client status sshd and confirm the IP appears under "Banned IP list".
  4. Check UFW: sudo ufw status numbered should show a REJECT or DENY rule from Fail2Ban.
  5. Unban when done: sudo fail2ban-client set sshd unbanip TEST_IP.

Common failure modes

  • Wrong log path after deploy: Symlink changes break jails silently. Re-check paths after every major release.
  • Backend mismatch: Use backend = systemd for journal-based services on Ubuntu 24.04. File-based logs need backend = auto or polling.
  • IPv6 ignored: Ensure allowipv6 = auto in fail2ban.conf if your server accepts v6 traffic.
  • Cloudflare in front: Fail2Ban sees Cloudflare IPs, not visitors. Restore real IPs in Nginx first, or ban at the CDN edge instead.
  • Log rotation: Fail2Ban handles rotated logs when paths are correct. Custom app logs need logrotate configs too.

Send ban notifications by email if you run Postfix or use a webhook action. For small teams without a SOC, a daily cron that dumps fail2ban-client status into your monitoring channel is enough. Our Ubuntu server monitoring guide covers lightweight patterns that fit budget VPS hosts in Nepal and abroad.

Fail2Ban Verify Checklist1. Edit configjail.local2. Test regexfail2ban-regex3. Reloadclient reload4. Simulatetrigger banCheck: fail2ban-client statusConfirm banned IP and UFW ruleProduction: monitor weeklyLog paths valid after each deploy
Ubuntu Fail2Ban configuration guide verification workflow before trusting production jails

Keep Fail2Ban logs in your backup scope. They help forensics after an incident. Our Ubuntu server backup strategies article includes /var/log/fail2ban.log in typical file lists. For client portals handling sensitive documents, like Mijar Law Associates, layered controls matter more than any single tool.

Integrate with UFW cleanly

Ubuntu's default Fail2Ban package ships a ufw ban action. Confirm it is set in [DEFAULT]:

banaction = ufw

UFW must be enabled first. Fail2Ban inserts numbered rules at the top. Do not hand-edit those entries. Use fail2ban-client unbanip instead. The Ubuntu community documentation on Fail2ban covers package-specific paths for LTS releases.

How does Fail2Ban fit into a full Ubuntu server security stack?

Fail2Ban handles credential stuffing and scanner noise. It does not patch PHP, harden TLS, or fix weak passwords. Treat it as reactive automation on top of baseline controls.

A sensible 2026 stack for PHP 8.3+ or Laravel 12/13 on Ubuntu looks like this:

  • UFW allowing only 22 (or custom SSH), 80, and 443.
  • SSH key auth only, root login disabled.
  • Fail2Ban jails for SSH, web auth, recidive, and CMS endpoints.
  • Automatic security updates via unattended-upgrades.
  • Strong app passwords — generate them with our password generator and store in a vault.
  • TLS 1.3 on Nginx or Apache with valid Let's Encrypt certs.
  • Off-site backups and tested restore paths.

For ongoing maintenance after launch, support and maintenance contracts should include Fail2Ban log review and jail tuning. Attack patterns shift. A jail that worked in 2024 may need new filters after a framework upgrade changes log formats.

If you host on a budget VPS in Nepal, expect Rs 1,500–3,000/month (~USD 11–22) for a basic box. Fail2Ban adds negligible overhead on a 1 GB RAM instance. CPU spikes usually mean overly broad regex or huge log files without rotation. Trim jails you do not need. Point high-volume access logs to lightweight filters only.

Document your ignoreip list and jail choices in your internal runbook. The next developer—or you, six months later—should not reverse-engineer production from memory. I keep a short server README beside Deployer configs on shared EC2 infrastructure. That single habit has saved hours during emergency lockout scares.

Key Takeaways

  • Install Fail2Ban from apt, then override settings in jail.local or jail.d/*.local — never edit jail.conf directly.
  • Always enable sshd, add web jails matching Nginx or Apache, and turn on recidive for repeat offenders.
  • Whitelist trusted IPs in ignoreip before testing bans so you do not lock yourself out of production.
  • Test every custom filter with fail2ban-regex before reloading the daemon.
  • Fail2Ban complements UFW and SSH hardening — it does not replace them or stop volumetric DDoS attacks.
  • Re-verify log paths after every Deployer release or log rotation change.

People Also Ask

Does Fail2Ban work with UFW on Ubuntu?

Yes. Set banaction = ufw in your Fail2Ban defaults. Fail2Ban inserts temporary deny rules through UFW commands. When the ban expires, the rule is removed automatically. Enable UFW before activating jails.

How long does Fail2Ban ban an IP address?

Duration is controlled by bantime in each jail. Values accept seconds or suffixes like 10m, 1h, and 1d. SSH jails often use 24 hours on production servers. The recidive jail can extend repeat bans to one week or more.

Can Fail2Ban block WordPress login attacks?

Yes. Enable the bundled wordpress jail or write a custom filter matching wp-login.php 403/404 patterns in Nginx access logs. Pair it with a login rate limit plugin for defense in depth. Fail2Ban catches IPs that hammer the endpoint from outside.

What happens if Fail2Ban bans my own IP?

You lose SSH and HTTP access from that IP until the ban expires or an admin unbans you. Use your VPS provider's web console to run fail2ban-client set JAIL unbanip YOUR_IP. Prevent this by listing trusted addresses in ignoreip and testing from a separate machine.

Ship a hardened Ubuntu server with confidence

This Ubuntu Fail2Ban configuration guide gives you copy-paste jails, custom filter patterns, and a verification workflow that works on real production stacks. Start with SSH and recidive, match web jails to your log paths, and test before you rely on any ban rule. If you want Fail2Ban wired into a full LEMP or Laravel deploy on Ubuntu—with UFW, TLS, backups, and monitoring handled together—contact us or review our Linux system administration and hosting setup services. A few hours of correct configuration prevents weeks of cleanup after a brute-force breach.

Frequently Asked Questions

Fail2Ban is a log-parsing daemon. It watches authentication failures in system and application logs, counts failed attempts inside a time window, and tells the firewall to block offending IPs temporarily.

Install from official Ubuntu repositories with apt update and apt install fail2ban, then enable the service with systemctl enable --now fail2ban. Confirm the daemon is active with systemctl status fail2ban before tuning jails. Copy jail.conf to jail.local rather than editing jail.conf directly, because package upgrades overwrite jail.conf. Set global defaults in the DEFAULT section at the top of jail.local so per-jail sections inherit bantime, findtime, maxretry, banaction, backend, and ignoreip unless overridden. Treat this as a standard step in your Ubuntu server setup checklist, right after UFW and SSH key authentication.

Never edit jail.conf directly on Ubuntu. Package upgrades overwrite it and you lose custom settings silently. Always override in jail.local or drop files under jail.d/. Copy the stock file once with cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local, then edit jail.local or add focused files like jail.d/laravel-auth.local for individual jails. This pattern keeps upgrades safe and makes production diffs easy to review. Document your ignoreip list and jail choices in an internal runbook so the next developer does not reverse-engineer production from memory six months later.

Enable the smallest set covering real attack surfaces. Always turn on the sshd jail with maxretry 3 and bantime 24h, paired with key-only SSH and disabled password auth. For Nginx stacks, enable nginx-http-auth on the error log and nginx-botsearch on access logs. Apache hosts need apache-auth and apache-badbots with log paths matching virtual host config. WordPress sites benefit from the wordpress jail. Enable recidive to ban repeat offenders for one week by reading fail2ban.log. Extra jails add parsing load with little gain on quiet sites, so match your actual web stack rather than enabling everything.

Duration is set by bantime in each jail. Values accept suffixes like 10m, 1h, 1d, or 1w. Production SSH often uses 24 hours; recidive can extend repeat offenders to one week.

Yes. Set banaction = ufw in DEFAULT, enable UFW first, and Fail2Ban inserts temporary deny rules that expire automatically when bans end.

Defaults are a starting point, not final policy. For production, SSH typically uses maxretry 3, findtime 10m, and bantime 24h. Web auth jails often use maxretry 5 and bantime 1h. Dev or staging can stay lenient with 10-minute bans. Enable recidive with bantime 1w, findtime 1d, and maxretry 3 to catch IPs rotating through multiple jails. Aggressive bans reduce scanner noise on high-traffic eCommerce hosts but can block shared NAT users. Lenient settings waste CPU parsing logs that never produce blocks. Fail2Ban is not a DDoS tool; volume attacks need CDN or upstream filtering instead.

Stock filters miss framework-specific login routes. Create a filter INI under /etc/fail2ban/filter.d/ with failregex lines matching your Laravel log format, ensuring failed auth attempts write consistent messages to storage/logs/laravel.log. Test patterns with fail2ban-regex against the log file before enabling the jail. Then add a jail under jail.d/ pointing logpath at your actual deploy path. On Deployer 7 releases, target the shared storage symlink, not an old release folder, because stale paths are a common post-deploy mistake. Reload with fail2ban-client reload and verify with fail2ban-client status after every config change.

Run fail2ban-client status and confirm each enabled jail appears. Check individual jail settings with fail2ban-client get sshd bantime and maxretry. Simulate a ban safely by adding your test IP to ignoreip or using a disposable VPS as the attacker, then trigger failed SSH logins from that machine. On the server, run fail2ban-client status sshd and confirm the IP under Banned IP list. Verify UFW shows a REJECT or DENY rule with ufw status numbered. Unban when finished with fail2ban-client set sshd unbanip TEST_IP. Never restart Fail2Ban during an active ban test from your own IP without ignoreip set first.

You lose SSH and HTTP access from that IP until the ban expires or an administrator removes it. Use your VPS provider web console to run fail2ban-client set JAIL unbanip YOUR_IP if locked out. Prevent this by whitelisting trusted addresses in ignoreip, including your deploy runner and home IP, before testing bans. Keep console access through your VPS provider as backup during tuning. A typo in ignoreip can lock you out during testing, so verify the list carefully. Test from a separate machine when possible rather than hammering production SSH from your daily workstation without protection.

The most common cause is a wrong log path, especially after Deployer releases when symlink targets change and jails silently stop matching lines. Re-check logpath after every major release. Backend mismatch also breaks jails: use backend = systemd for journal-based services on Ubuntu 24.04, while file-based logs need backend = auto or polling. If Cloudflare sits in front, Fail2Ban sees Cloudflare IPs, not visitors, so restore real client IPs in Nginx first or ban at the CDN edge. Zero currently banned is normal on quiet servers, but zero total banned over weeks usually signals a broken path or filter.

Yes. Enable the bundled wordpress jail with maxretry 3, pointing at auth.log and Nginx access.log, or write a custom filter matching wp-login.php probing patterns. Pair Fail2Ban with a login rate-limit plugin for defense in depth.

Not without extra configuration. Fail2Ban reads your web server logs, and behind Cloudflare those logs often show Cloudflare edge IPs instead of real visitor addresses. Banning those IPs blocks legitimate CDN traffic paths, not the attacker. Restore real client IPs in Nginx before relying on web jails, or handle abuse at the CDN edge instead. SSH and direct server jails still work normally because they do not depend on proxied HTTP headers. For mixed stacks, treat Fail2Ban as server-side credential-stuffing protection and use upstream filtering for volumetric or distributed scanner floods.

Fail2Ban itself is free and adds negligible overhead on a basic 1 GB RAM VPS. Expect Rs 1,500–3,000 per month (~USD 11–22) for a budget box suitable for Laravel, WordPress, or Apache PHP-FPM stacks where Fail2Ban runs alongside UFW. CPU spikes usually mean overly broad regex patterns or huge log files without rotation, not the daemon itself. Trim jails you do not need and point high-volume access logs to lightweight filters only. For small teams without a SOC, a daily cron dumping fail2ban-client status into a monitoring channel is enough operational visibility without paid security tooling.

No on both counts. Fail2Ban automates temporary firewall reactions to abuse patterns found in logs; UFW still handles baseline port policy. Set banaction = ufw so Fail2Ban inserts numbered rules at the top, but enable UFW first and never hand-edit those entries—use fail2ban-client unbanip instead. Fail2Ban does not patch PHP, harden TLS, or fix weak passwords, and it cannot stop volumetric DDoS attacks that overwhelm log parsing or network capacity. Treat it as one reactive layer in a wider hardening plan alongside SSH key auth, automatic security updates, valid Let's Encrypt TLS, off-site backups, and rate limits at the reverse proxy where appropriate.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: