Fail2Ban: SSH and HTTP Protection Setup

16 min read 3,050 words
How to Use Fail2Ban to Protect SSH and HTTP Services featured image

Brute-force attacks on SSH services represent one of the most persistent threats facing Linux servers connected to the internet. Automated scripts scan for open SSH ports around the clock, cycling through username and password combinations in hopes of guessing weak credentials. Fail2Ban provides an effective layer of defence against these attacks by monitoring authentication logs and automatically blocking IP addresses that exhibit malicious behaviour.

This guide covers how to install and configure Fail2Ban to protect SSH and web services on Ubuntu servers. It walks through the complete setup process, explains how jails work, covers common configuration mistakes that reduce effectiveness, and describes the steps needed to harden your configuration for production use.

How Fail2Ban Works

Fail2Ban monitors log files for patterns that match known attack signatures. When a pattern is detected repeatedly, Fail2Ban updates the server firewall to block the offending IP address. The blocking is temporary by default but can be extended for persistent attackers who return after their ban expires.

The tool operates on a concept of jails. Each jail monitors a specific log file for specific patterns and applies an action when those patterns match. The default installation includes sensible jail configurations for SSH, Apache, and Nginx out of the box. You can enable, disable, or customise these jails based on your server setup and traffic patterns.

When Fail2Ban identifies an IP that exceeds the failure threshold within the defined time window, it adds that IP to the firewall rules managed by iptables or nftables. Connections from the blocked IP are refused at the network level, preventing the attacker from consuming server resources or attempting further logins. This automated response happens within seconds of detecting the malicious behaviour, which is far faster than manual intervention could achieve.

Installing Fail2Ban on Ubuntu

The installation process is straightforward on Ubuntu. Update your package list and install the package from the default repository.

apt update && apt install fail2ban

After installation, the Fail2Ban service starts automatically. You can verify the service is running with this command.

systemctl status fail2ban

If the service is not running, start it manually.

systemctl start fail2ban

For servers that run headless or require Fail2Ban to start on boot without a GUI session, ensure the service is enabled.

systemctl enable fail2ban

The package installs with sensible defaults that work for most configurations. However, reviewing and customising the default settings for your specific environment improves effectiveness significantly.

Understanding the Configuration Structure

Fail2Ban stores its configuration in /etc/fail2ban/. The main configuration file is jail.conf, which contains default settings for all available jails. You should never edit this file directly because package updates can overwrite your changes without warning.

Instead, create a jail.local file in the same directory. Settings in this file override the defaults in jail.conf. This approach keeps your customisations separate and ensures they survive system updates. All changes should go into jail.local rather than the defaults file.

The jail.local file uses the same syntax as jail.conf. Here is a basic structure for overriding SSH jail settings.

[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

The settings control how Fail2Ban behaves. maxretry defines the number of failures allowed within the findtime window before a ban is issued. bantime specifies how long the ban lasts in seconds. The values above represent a reasonable starting point for SSH protection on most servers.

The ignoreip directive allows you to specify IP addresses or ranges that should never be banned. Adding your office or home IP address here prevents accidental self-blocking while you test or work on your server.

ignoreip = 127.0.0.1/8 192.168.1.0/24

Replace the example ranges with your actual IP addresses. This setting supports both individual IP addresses and CIDR notation for networks.

Configuring HTTP Protection for Nginx or Apache

Fail2Ban can also protect web servers against abuse, including aggressive scrapers, vulnerability scanners, and denial-of-service attempts. HTTP attacks typically happen faster than SSH attacks because a single machine can make hundreds of requests per minute without triggering account lockouts. For Apache servers specifically, reviewing your Apache security configuration alongside Fail2Ban provides more comprehensive protection.

A normal user loading a web page generates fewer than 10 requests per minute. An automated script can easily exceed 100 requests in the same timeframe. Monitoring access logs for this behaviour lets you block malicious traffic before it affects server performance or costs you bandwidth and processing resources.

The findtime for HTTP bans should be shorter than for SSH because HTTP attacks unfold more quickly. A five-minute window and a threshold of 100 requests will catch aggressive scrapers and scripted attacks without affecting normal users who refresh pages frequently.

[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 100
bantime = 600
findtime = 300

For Apache, replace the log path with the corresponding Apache access log location. On Ubuntu, this is typically /var/log/apache2/access.log or /var/log/apache2/other_vhosts_access.log depending on your logging configuration.

[apache-auth]
enabled = true
port = http,https
logpath = /var/log/apache2/access.log
maxretry = 100
bantime = 600
findtime = 300

Adjust the maxretry value based on your observed traffic patterns. Servers with API endpoints or heavy legitimate traffic may require higher thresholds to avoid blocking real users. Monitor your logs during the first few days after enabling HTTP jails to understand what normal traffic looks like on your server.

Application-level rate limiting can supplement Fail2Ban for protecting specific endpoints that require finer control than network-level blocking provides. This approach works particularly well for API services where you need to limit requests per user or per token rather than per IP address.

Enabling and Testing Your Jails

After creating your jail.local configuration, restart the Fail2Ban service to apply the changes.

systemctl restart fail2ban

List all configured jails and their status using the Fail2Ban client.

fail2ban-client status

This command shows which jails are active and how many IPs are currently banned. To check the status of a specific jail, such as the SSH jail, run this.

fail2ban-client status sshd

The output shows the total number of failures that triggered bans and lists the currently banned IP addresses. Reviewing this information regularly helps you understand what kind of traffic your server receives and whether your configuration needs adjustment.

Setting Up Email Notifications

Configuring Fail2Ban to send email notifications confirms that the service is working and alerts you to active attacks. Without notifications, you may not realise Fail2Ban is blocking traffic unless you check the logs manually, which most people do infrequently.

The default action for most jails bans the IP silently. To receive notifications, change the action to include whois information and log excerpts.

action = %(action_mwl)s

This configuration bans the offending IP and sends an email containing the whois record and relevant log lines. For this to work, your server must be able to send email. Configuring Postfix or another mail transfer agent ensures ban notifications reach your inbox rather than failing silently.

If your server does not have email configured, logs are still written to /var/log/fail2ban.log. You can monitor this file directly or set up log rotation to manage file sizes over time.

tail -f /var/log/fail2ban.log

Reading log entries helps you understand what patterns triggered bans and whether your thresholds are set appropriately. Persistent attack patterns in your logs may indicate the need for additional jail configurations or more restrictive settings.

Common Configuration Mistakes That Reduce Effectiveness

Several configuration errors commonly reduce Fail2Ban's effectiveness or cause unexpected blocking of legitimate users. Avoiding these mistakes helps you get the most from the tool.

  • Setting maxretry too low: Legitimate users on unstable network connections may trigger multiple connection attempts, especially when an SSH client retries automatically. Setting maxretry to at least 3 for SSH prevents accidental bans of real users who have temporary connectivity issues.
  • Forgetting to whitelist your own IP: Accidentally banning yourself while testing or during normal work is frustrating and potentially disruptive. Add your office or home IP address to the ignoreip directive in your jail.local file to prevent self-blocks.
  • Incorrect log file paths: Fail2Ban silently takes no action if the log path in your jail configuration does not match the actual log file location. Verify paths carefully, especially if your distribution or web server uses non-standard logging locations.
  • Editing jail.conf directly: Changes made to jail.conf are overwritten during package updates. Always use jail.local for customisations to preserve settings across updates and make your configuration portable.
  • Ignoring ban repeat offenders: Some attackers cycle through IP addresses or wait for bans to expire before resuming. Persistent attackers should be added to a permanent block list at the firewall level rather than relying on Fail2Ban to re-ban them repeatedly.
  • Setting findtime too long: A long findtime window combined with a low maxretry can cause Fail2Ban to miss attack patterns that span across the window boundary. Keep findtime proportional to your expected traffic patterns.

Hardening Fail2Ban for Production Servers

The default Fail2Ban configuration is a useful starting point, but production servers benefit from more restrictive settings. Adjusting the thresholds based on your actual traffic patterns and security requirements strengthens your defence significantly. Combining Fail2Ban with a broader server hardening checklist helps you address multiple security layers together.

For SSH access exposed to the internet, set maxretry to 3 and bantime to at least 3600 seconds, which is one hour. For servers that experience repeated targeted attacks, consider extending the ban time to 86400 seconds, which is 24 hours, for repeat offenders. The findtime of 600 seconds (10 minutes) remains appropriate for most SSH configurations.

Use the Fail2Ban client to manually ban IP addresses that you observe scanning your server, even if they have not yet triggered an automatic ban. This proactive approach stops persistent scanners before they can catalogue your server's vulnerabilities.

fail2ban-client set sshd banip 192.0.2.100

Replace 192.0.2.100 with the IP address you want to block. After manually banning an IP, review your logs to understand why it was flagged and whether it represents a genuine threat or a misconfiguration.

Combine Fail2Ban with a properly configured firewall for layered protection. UFW (Uncomplicated Firewall) on Ubuntu works well alongside Fail2Ban, providing baseline firewall rules while Fail2Ban dynamically blocks IP addresses based on observed behaviour. Reviewing both configurations together gives you a clearer picture of your server's exposure and helps you identify gaps in your protection.

ufw status verbose

This command shows your current UFW rules, which should complement rather than conflict with Fail2Ban's dynamic blocking. If you are setting up a new server, hardening Ubuntu after install covers the essential steps for a secure baseline.

Integrating Fail2Ban with Secure SSH Configuration

Fail2Ban is most effective as part of a broader security strategy rather than as a standalone solution. Combining it with SSH key authentication and secure SSH configuration creates multiple layers of defence. Even if Fail2Ban fails or is temporarily unavailable, strong SSH configuration continues to protect your server.

Disabling password authentication for SSH and using key-based login eliminates the primary attack vector that Fail2Ban protects against. Even with Fail2Ban in place, strong SSH configuration reduces your attack surface significantly. Configuring SSH securely covers the key settings you should implement alongside Fail2Ban.

You should also restrict SSH access to specific IP addresses or ranges where possible, limiting who can attempt authentication at all. If your office or home has a static IP address, configuring your firewall to allow SSH only from that address blocks all other SSH connection attempts before they reach Fail2Ban or the SSH daemon itself.

Regularly reviewing /var/log/fail2ban.log helps identify patterns in attack traffic and refine your configuration over time. Look for IP ranges that appear repeatedly, scan schedules that suggest automated tools, and any new attack signatures that may require additional jail configurations.

When you identify persistent attackers, consider adding their IP ranges to a permanent block list in your firewall rather than relying on Fail2Ban to re-block them each time. This approach reduces processing overhead and ensures these IPs remain blocked even during Fail2Ban restarts or temporary outages.

When Fail2Ban Is Not Enough

Fail2Ban works well against attacks where a single IP address generates many requests. However, it cannot stop distributed attacks where each IP address makes only a small number of requests. In a distributed brute-force attack, thousands of different IP addresses might each attempt just one or two logins, staying below the maxretry threshold.

For protection against distributed attacks, consider cloud-based DDoS mitigation services that can absorb and filter malicious traffic before it reaches your server. These services operate at the network edge and can distinguish between legitimate traffic and attack traffic based on characteristics that individual server logs do not reveal.

Fail2Ban also cannot protect against attacks that exploit application vulnerabilities or credential stuffing where attackers use username and password combinations stolen from other services. Application-level security measures, proper input validation, and multi-factor authentication address these threat vectors more effectively than network-level blocking alone.

For Apache servers specifically, ensuring your HTTP daemon configuration follows security best practices reduces the attack surface available to exploit. Fail2Ban handles automated attacks, but a secure default configuration prevents many attacks from succeeding even if they slip through.

Maintaining Your Fail2Ban Setup Over Time

Fail2Ban configuration requires occasional review as your server usage evolves. Traffic patterns change, new services are added, and attack techniques shift. A configuration that works well initially may need adjustment as your server grows and attracts more attention from automated scanners.

When adding new services to your server, consider whether they expose new attack surfaces. A new web application, API endpoint, or management interface may benefit from its own Fail2Ban jail. Review the available jail templates and adapt them for your specific log formats and access patterns.

Keep your Fail2Ban installation updated through regular system package updates. New jail definitions and pattern matching improvements are included in updates that address emerging threats. Subscribe to security mailing lists for your distribution to stay informed about updates that affect Fail2Ban or its dependencies.

Back up your jail.local file before performing major system upgrades. While the file should be preserved in most cases, having a backup ensures you can restore your configuration quickly if anything goes wrong during the upgrade process. Store backups in a location separate from the server itself, such as a local machine or cloud storage.

Related practical reading

These related guides can help you connect this topic with the wider website, server, security, and support decisions around it.

Frequently Asked Questions

Can Fail2Ban prevent distributed denial-of-service attacks?
Fail2Ban is not effective against distributed DoS attacks because each attacking IP makes only a small number of requests, staying below the threshold that triggers a ban. For distributed attacks, you need cloud-based DDoS protection that can filter traffic at the network edge before it reaches your server. Fail2Ban works well against targeted attacks from a smaller number of IPs, which represents the more common threat for most servers.
How long should I set the ban time?
For SSH, a ban time of at least one hour (3600 seconds) is appropriate for most servers. If you experience repeated attacks from the same IP addresses, you can extend this to 24 hours for persistent offenders. For HTTP protection, shorter ban times of 10 to 30 minutes are usually sufficient to disrupt automated attacks without causing issues for legitimate users who may be sharing an IP address with a blocked attacker.
Should I change the default SSH port?
Changing the SSH port from the default 22 reduces the volume of automated login attempts in your logs because many bots scan only port 22. However, this is security through obscurity rather than a security control, and it does not protect against targeted attacks. Fail2Ban remains necessary regardless of which port SSH uses, and you should always combine port changes with strong authentication and key-based login.
How do I unban an IP address accidentally?
You can manually unban an IP address using the Fail2Ban client. Replace sshd with your jail name if you are using a different configuration.
Does Fail2Ban work with IPv6?
Yes, Fail2Ban supports both IPv4 and IPv6 addresses. However, IPv6 addresses are more numerous, which can make certain types of bans less effective. If your server uses both protocols, ensure your firewall rules and Fail2Ban configuration handle IPv6 traffic appropriately. Some configurations may require specific attention to IPv6 for complete coverage.
How can I test whether Fail2Ban is working correctly?
You can test Fail2Ban by attempting to trigger a ban yourself from a known IP address, such as your home connection. Attempt several failed SSH logins and verify that your IP gets blocked. Check the status output with fail2ban-client status sshd to confirm the ban was recorded. Remember to add your IP to ignoreip if you plan to test regularly, and use the unban command to restore access after testing.
What happens when Fail2Ban restarts or crashes?
When Fail2Ban restarts, it reads the jail configuration and rebuilds firewall rules from current bans. However, bans that were active during an outage are not automatically restored unless Fail2Ban has persistence configured or your system saves state. For critical servers, monitoring Fail2Ban's status and setting up alerting for service failures ensures you can respond quickly to any interruption in protection.