Skip to main content
Attackers can steal data, spread malware (spyware or ransomware), or even take a site offline. While many bots are benign (search engine crawlers), others scrape content, post spam, or generate fake reviews. Blocking unwanted traffic early reduces risk and preserves resources.
An infographic titled "Hackers" showing a hooded attacker at computer screens with a skull emblem. Above are icons and labels for "Steal data," "Spread spyware and ransomware," and "Take down the whole site."
A common defensive stack combines authentication, service-level controls, and automated blocking. One service-level control is blocking IPs and ranges at the NGINX layer to prevent known bad actors or unexpected network ranges from reaching your application.
A diagram titled "Blocking Traffic" showing three sources—IPs, Bots, and Network Traffic—being routed toward a website and stopped by a red prohibited symbol. Colorful icons represent each traffic source and a stylized webpage on the right shows the blocked content.

NGINX access control: allow / deny

NGINX uses the http_access module to control access via allow and deny directives (see the official docs: https://nginx.org/en/docs/http/ngx_http_access_module.html). Place these directives inside http, server, or location blocks to permit or block traffic by IPv4/IPv6 address or CIDR block. Example — allow two specific IPv4 addresses and deny all other traffic:
To block a range, use CIDR prefixes. Example — deny a /24 range and allow a specific /24 inside a location:
Use CIDR to express address scope efficiently:
  • /32 — single IPv4 address
  • /24 — block of 256 addresses (e.g., 203.0.113.0 through 203.0.113.255)
CIDR quick reminder: /32 = one IPv4 address; /24 = 256 addresses. Use CIDR notation to manage large address sets instead of listing many single addresses.
However, adding many allow/deny rules directly to NGINX configuration files does not scale well. Attackers rotate IPs, and long lists make configuration brittle and hard to maintain.
A slide titled "Not Scalable" showing two columns labeled "Allow" (with a green check) and "Deny" (with a red X) listing several IP addresses under each. The allow column contains five IPs and the deny column contains two IPs.

Automated blocking with Fail2Ban

For many deployments, using an automated agent to monitor logs and apply short-term bans is more effective than static lists. Fail2Ban (https://www.fail2ban.org) watches log files for suspicious patterns and updates host firewall rules (iptables, nftables, or firewalld) to block offending IPs temporarily.
The image shows the Fail2Ban logo: a small cartoon house with a red "stop" sign featuring a raised hand, above the text "FAIL2BAN." A caption below explains it enhances server security by blocking malicious IPs, especially against brute‑force attacks.
Fail2Ban is especially effective against brute-force attempts and repeated abuse because it:
  • Parses logs for configurable regex patterns (filters).
  • Applies bans when thresholds are exceeded (jails).
  • Unbans automatically after a configured bantime.
Example runtime output (tailing the Fail2Ban log):

Installing Fail2Ban

Common installation commands: After installation, create a local override and configure jails:

Example Fail2Ban jails for NGINX

Add jails to jail.local to enable NGINX-related monitoring:
Block known bad bots with a longer ban:
Rate-limit excessive requests:
Fail2Ban filters are stored in /etc/fail2ban/filter.d. Many filters are included by default.
Example filter file listing (illustrative):
Sample snippet from nginx-http-auth.conf (truncated):
These filters use regular expressions to match authentication failures or other suspicious log lines. When the configured thresholds (e.g., maxretry within findtime) are exceeded, Fail2Ban triggers the ban action.

Managing Fail2Ban and banned IPs

Check jail status and currently banned IPs:
Example output:
To unban an IP:
Because Fail2Ban operates on host logs and firewall rules, it typically requires no change to application configurations to be effective.
Fail2Ban depends on host log files and the host firewall. It may not work as expected in ephemeral container environments or Kubernetes clusters where logs are aggregated or networking is managed by the platform. For containers, consider ingress rate limiting, a Web Application Firewall (WAF), or platform-native network policies.

Quick reference

In this lesson you learned:
  • How to use NGINX allow/deny with CIDR notation to block IPs or ranges.
  • Why long static lists in NGINX are hard to maintain and scale poorly.
  • How Fail2Ban dynamically blocks abusive IPs by monitoring logs and updating firewall rules.
  • Basic Fail2Ban configuration patterns and how to inspect/unban IPs.
If you’re testing locally on Ubuntu:
  1. Install Fail2Ban (sudo apt install fail2ban).
  2. Copy jail.conf to jail.local and enable the NGINX jails you need.
  3. Tail /var/log/fail2ban.log and /var/log/nginx/access.log to verify detection and bans.
Useful references:

Watch Video