
September 09, 2026
13 min read
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.
apt install fail2ban, copies jail.local from jail.conf, enables jails like sshd and nginx-http-auth, sets bantime and findtime, then verifies bans with fail2ban-client status.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.
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.
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.
| Setting | Dev / Staging | Production SSH | Production Web |
|---|---|---|---|
maxretry | 10 | 3 | 5 |
findtime | 10m | 10m | 10m |
bantime | 10m | 24h | 1h |
recidive bantime | off | 1w | 1w |
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.
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
- Add your test IP to
ignoreipif needed, or use a disposable VPS as the attacker. - From the test machine, run
ssh wronguser@your-serverthree times with bad passwords. - On the server, run
sudo fail2ban-client status sshdand confirm the IP appears under "Banned IP list". - Check UFW:
sudo ufw status numberedshould show a REJECT or DENY rule from Fail2Ban. - 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 = systemdfor journal-based services on Ubuntu 24.04. File-based logs needbackend = autoor polling. - IPv6 ignored: Ensure
allowipv6 = autoinfail2ban.confif 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.
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.localorjail.d/*.local— never editjail.confdirectly. - Always enable
sshd, add web jails matching Nginx or Apache, and turn onrecidivefor repeat offenders. - Whitelist trusted IPs in
ignoreipbefore testing bans so you do not lock yourself out of production. - Test every custom filter with
fail2ban-regexbefore 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
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.

