DEV Community

Cover image for Stop Brute-Force and Bad Bots: The Fail2ban Guide for SSH & Nginx
Shakhzhakhan Maxudbek
Shakhzhakhan Maxudbek

Posted on Edited on Originally published at args.tech

Stop Brute-Force and Bad Bots: The Fail2ban Guide for SSH & Nginx

Disclaimer: Host-Level vs Edge Security

Note: This guide helps you configure host-level security. Fail2ban is an excellent tool for stopping brute-force attacks, script kiddies, and aggressive crawlers locally. However, it is not a complete alternative to Edge Security services or Web Application Firewalls (WAF) such as Cloudflare, AWS Shield, or Akamai.

For high-traffic production websites, creating thousands of firewall rules dynamically (which Fail2ban does) can impact server performance. For "cheap and cheerful" VPS protection, Fail2ban is perfect. For enterprise-grade protection, consider using a dedicated WAF.

Introduction

Is your Virtual Private Server (VPS) constantly under SSH brute-force attacks? Or perhaps "bad bots" are crawling your site, looking for vulnerabilities like /admin, /wp-login.php, or .env files?

The solution is Fail2ban.

Fail2ban is an intrusion prevention software framework that protects computer servers from brute-force attacks. It scans log files (e.g., /var/log/auth.log or /var/log/nginx/error.log) and bans IPs that show malicious signs-too many password failures, seeking exploits, etc.-by updating system firewall rules to reject new connections from those IP addresses.

Step 1: Install Fail2ban

Before installation, it is always a good practice to update your package repository.

Update lists and install the package (Debian/Ubuntu):

sudo apt update && sudo apt install -y fail2ban
Enter fullscreen mode Exit fullscreen mode

If you are using CentOS/RHEL/AlmaLinux, you need the EPEL repository first:

sudo yum install -y epel-release && sudo yum install -y fail2ban
Enter fullscreen mode Exit fullscreen mode

Start the service and enable it to run on boot:

sudo systemctl enable --now fail2ban
Enter fullscreen mode Exit fullscreen mode

Step 2: Global configuration

Fail2ban installs with a default configuration file named jail.conf. Do not edit this file directly, as it will be overwritten during updates. Instead, we create a copy called jail.local.

Create the local configuration file:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Enter fullscreen mode Exit fullscreen mode

Now, let's configure the default behavior. We need to set the ignoreip (IPs that should never be banned) and the ban duration.

Open the file for editing:

sudo nano /etc/fail2ban/jail.local
Enter fullscreen mode Exit fullscreen mode

Find the [DEFAULT] section and adjust the settings. Crucial: Add your own home/office IP address to ignoreip so you don't lock yourself out!

[DEFAULT]
# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts.
# ALWAYS add your own IP here (e.g., 123.123.123.123)
ignoreip = 127.0.0.1/8 ::1 your_external_ip_address

# "bantime" is the number of seconds that a host is banned.
# 3600 = 1 hour. 86400 = 1 day.
bantime  = 3600

# A host is banned if it has generated "maxretry" during the last "findtime"
findtime = 10m

# "maxretry" is the number of failures before a ban occurs.
maxretry = 3
Enter fullscreen mode Exit fullscreen mode

Step 3: Protecting SSH

The most important jail is for SSH. It monitors authentication logs for failed login attempts.

Scroll down to the [sshd] section in jail.local (or add it if missing) and ensure it is enabled:

[sshd]
enabled = true
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
Enter fullscreen mode Exit fullscreen mode

Step 4: Protecting Nginx

Fail2ban comes with pre-defined filters for Nginx. We will enable three common protections: Authentication failures, "Bot Search" (scanners looking for scripts), and Bad Bots (User-Agents).

Add these blocks to your /etc/fail2ban/jail.local file.

Nginx HTTP auth

Bans IPs that fail to log in to password-protected areas of your site (Basic Auth):

[nginx-http-auth]
enabled = true
port    = http,https
logpath = %(nginx_error_log)s
Enter fullscreen mode Exit fullscreen mode

Nginx bot search

This acts as a trap for scanners. It looks for 404 errors on commonly scanned paths (like setup.php, admin/, wp-login.php). If an IP hits too many non-existent scripts, it gets banned.

[nginx-botsearch]
enabled  = true
port     = http,https
logpath  = %(nginx_error_log)s
maxretry = 2
Enter fullscreen mode Exit fullscreen mode

Step 5: Blocking bad User-Agents

Sometimes you want to block bots based on their User-Agent header (e.g., Python scripts, Go-http-client, or known scraping tools).

First, create a filter definition. Create a new file /etc/fail2ban/filter.d/nginx-badbots-custom.conf:

sudo nano /etc/fail2ban/filter.d/nginx-badbots-custom.conf
Enter fullscreen mode Exit fullscreen mode

Paste the following definition. Warning: Be careful blocking curl, requests or Go-http-client if you use these tools for your own API interactions or health checks.

[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*HTTP.*"(?:%(badbots)s|%(badbotscustom)s)"$
ignoreregex =

# Standard patterns for bad bots
badbotscustom = Go-http-client\/.*|python-requests\/.*|Python\/.*|python-httpx\/.*|Scrapy\/.*|lychee\/.*
Enter fullscreen mode Exit fullscreen mode

Now, activate this jail in your jail.local:

[nginx-badbots-custom]
enabled  = true
port     = http,https
filter   = nginx-badbots-custom
logpath  = /var/log/nginx/access.log
maxretry = 1
bantime  = 86400
Enter fullscreen mode Exit fullscreen mode

Step 6: Apply and verify

After making changes to the configuration, restart the Fail2ban service.

Restart command:

sudo systemctl restart fail2ban
Enter fullscreen mode Exit fullscreen mode

Check the status of the server and listed jails:

sudo fail2ban-client status
Enter fullscreen mode Exit fullscreen mode

Check the detailed status of a specific jail (e.g., SSH), to see how many IPs are currently banned:

sudo fail2ban-client status sshd
Enter fullscreen mode Exit fullscreen mode

Conclusion

You have now added a significant layer of security to your VPS. Fail2ban will quietly work in the background, banning thousands of malicious IPs that attempt to guess your passwords or scan your Nginx server for vulnerabilities.

Did this save you an hour of debugging? Writing high-quality tech guides takes hours of research and testing. If you found this post valuable, you can support my work by buying me a coffee. Thank you!

Buy Me a Coffee at ko-fi.com

Top comments (0)