Skip to main content
In this lesson you’ll learn how to block and allow traffic for an example site (example.com) using Nginx allow / deny directives, and how to use fail2ban to automatically ban IPs that repeatedly fail authentication. The site exposes a protected /admin endpoint that uses HTTP Basic authentication; you can restrict access by IP in Nginx and automatically ban attackers with fail2ban. Key goals:
  • Use Nginx allow and deny to permit or block specific IP addresses or CIDR ranges.
  • Use fail2ban to automatically block IPs that repeatedly submit bad credentials, avoiding large, manually maintained deny lists.

Base Nginx configuration (HTTP -> HTTPS, TLS, headers, protected /admin)

Start with this base Nginx site configuration for example.com. It redirects HTTP to HTTPS, configures TLS, sets security headers, serves files from a document root, and protects /admin with HTTP Basic auth:
This configuration is the baseline used for the rest of the examples below.

Verify DNS/name resolution and test connectivity

On your client nodes (for example node01 and node02) ensure example.com resolves to your Nginx server by editing /etc/hosts:
Check connectivity with curl. Because the TLS certificate was issued with a local CA (e.g., mkcert), curl will not trust it by default. Example checks:
To bypass certificate verification for testing only, use -k (equivalent to --insecure):
Using -k disables certificate verification. Only use it for testing; do not use it in production scripts.
If you request the protected /admin without credentials, Nginx returns 401 Unauthorized:

Manually block a single IP with deny

To block a specific IP (for example node02 with IP 192.231.128.3), add a deny directive in the location / block. Example:
After editing the Nginx site file, test and reload Nginx:
Expected outcome:
  • node01 (allowed) → receives 200 OK.
  • node02 (denied) → receives 403 Forbidden.

Allow only one IP to access /admin and deny all others

To permit a single management IP (e.g., node01 at 192.231.128.12) to access /admin and deny everyone else, use allow followed by deny all inside the /admin location:
Notes:
  • Each allow and deny directive requires a trailing semicolon.
  • If the allowed client supplies an invalid username/password, Nginx will still return 401 Unauthorized because auth_basic runs after the allow/deny check.

Allow a whole subnet (CIDR) instead of many single IPs

Instead of maintaining many /32 entries, permit an entire subnet. For example, to allow the 192.231.128.0/24 network (which contains node01 and node02), use:
CIDR quick reference: Remember: include the trailing semicolon: allow 192.231.128.0/24;

Why not maintain long deny lists? Use fail2ban to automate bans

Manually maintaining long deny lists in Nginx becomes cumbersome and error-prone. fail2ban monitors logs (including Nginx error logs), detects repeated failures (such as failed HTTP Basic auth attempts), and adds temporary firewall rules (bans) for misbehaving IPs. Install and configure fail2ban (Debian/Ubuntu example):
Create a local config so package updates don’t overwrite your settings:
Enable and configure the nginx-http-auth jail by adding or editing a snippet in /etc/fail2ban/jail.local:
fail2ban option meanings:
Setting maxretry = 1 will ban after a single failed authentication attempt. For production, increase maxretry to reduce false positives and tune bantime to suit your environment.
Start/restart fail2ban and check the status:
Sample output for the nginx-http-auth jail:
To unban an IP:

When a client accesses /admin from a browser and submits incorrect credentials, the browser’s sign-in prompt appears. Repeated failed attempts will be detected by fail2ban and the IP will be banned according to your jail settings.
A browser screenshot showing a sign-in dialog for "https://example.com" with the username "admin" filled in and a masked password field, plus "Cancel" and "Sign In" buttons. The rest of the page is mostly blank.
After a failed attempt (or the number specified by maxretry), fail2ban will add the client’s IP to the banned list and access to /admin (and possibly other HTTP(S) ports) will be blocked until the ban expires or is removed.

Option: Let fail2ban handle blocking instead of large deny lists

If you want Nginx config to remain simple and prefer dynamic blocking, do not add allow / deny rules on the site root. Instead, rely on fail2ban jails to block offenders. Example server config without allow/deny:
This approach keeps Nginx configuration manageable and lets fail2ban dynamically add IP-level blocks in the firewall when repeated failures are detected.

Summary & best practices

  • Use Nginx allow/deny for small, static lists of trusted or blocked IPs.
  • Use CIDR ranges (/24, /16, etc.) to cover networks instead of many /32 entries.
  • For automated handling of attackers (e.g., repeated failed HTTP Basic auth attempts), use fail2ban to monitor Nginx logs and apply temporary bans.
  • Tune fail2ban maxretry and bantime to balance security and the risk of false positives in your environment.
Further reading:

Watch Video

Practice Lab