← Start of tutorial

WIUNIX ACADEMY

Fail2ban for Nginx: trustworthy logs, scoped bans and recovery

Page 6 of 6. Review the earlier steps and prerequisites before continuing.

YOUR SYSTEM. YOUR STEPS.

Where are you working?

Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.

Debian 12 LTSReviewed against official documentation ·

USE YOUR OWN VALUES

Configure this tutorial

Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.

Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.

Set values for my environment11 editable values

Find the failing layer

First distinguish no records, no matches, no decisions and no packet enforcement. Review logs locally; they contain personal IPs. A matched regex with no ban can mean ignoreip, an old timestamp, a threshold not reached or a different active configuration. An action error is not a successful ban. Never respond by flushing the firewall, allowing all proxies, disabling TLS or changing the regex to match every 4xx.

No new records / rotation

Check location routing, current file/inode and package reopen policy. A config test does not prove the request reached this location.

Bash
sudo nginx -t
sudo stat "/var/log/nginx/academy-auth.log"
sudo tail -n 12 "/var/log/nginx/academy-auth.log"
sudo cat /etc/logrotate.d/nginx
Parser or clock mismatch

Repeat only the synthetic regex test and inspect clock synchronization. Do not rewrite timestamps in real evidence.

Bash
timedatectl status
sudo fail2ban-regex "/srv/academy-fail2ban-lab/fixture.log" /etc/fail2ban/filter.d/academy-nginx-401.conf --usedns=no --print-all-missed
Daemon/action errors

Inspect service logs, resolved action and real rules. Never paste the complete configuration publicly.

Bash
sudo journalctl -u fail2ban --since "20 minutes ago" --no-pager
sudo fail2ban-client status academy-nginx
sudo fail2ban-client get academy-nginx actions
sudo nft list ruleset
19

LET’S BUILD

Recover without deleting the whole firewall

Use the independent console or retained session. First stop only academy-nginx, which asks its action to remove its own sets/rules and releases its bans. Then edit the local file to enabled=false for that stanza before any service restart; leave the fresh-lab SSH stanza as it was. If you need to release one misclassified client while keeping the jail, inspect its actual address in status and use the unban command syntax shown below with that exact address. The documentation address is illustrative and not a real client. Correct the cause/allowlist before re-enabling. Restarting a daemon with a persistent ban database may reinstate bans; do not treat reboot as recovery.

Bash

Dedicated lab host; Bash shell

sudo fail2ban-client set academy-nginx unbanip 192.0.2.60
sudo fail2ban-client stop academy-nginx
sudo nano /etc/fail2ban/jail.d/90-academy-nginx.local
sudo fail2ban-client -t
sudo nft list ruleset
How do I know it worked?

Only this jail is stopped and disabled persistently; unrelated rules/jails are preserved.

20

LET’S BUILD

Restore the changed files deliberately

If logging changes caused a problem, remove the added access_log line from the exact existing location, retain required inherited audit logging, and restore that affected virtual-host file from the private snapshot only after comparing concurrent changes. The panel extracts the snapshot into a separate private review directory, never over /etc. Remove the new format definition only after all references are removed. Test Nginx before reloading. Retire only this guide’s new filter/local override after disabling its jail. Do not restore a complete old /etc tree or uninstall a shared firewall package.

Bash

Dedicated lab host; Bash shell

set -e
sudo install -d -m 0700 "/srv/academy-fail2ban-lab/restore-review"
sudo tar -C "/srv/academy-fail2ban-lab/restore-review" -xpf "/srv/academy-fail2ban-lab/nginx-before.tar"
sudo diff -ru "/srv/academy-fail2ban-lab/restore-review/nginx" /etc/nginx || true
# Reconcile only the affected files in a protected editor.
sudo nginx -t && sudo systemctl reload nginx
How do I know it worked?

Affected files are reconciled, syntax passes and the old site behavior is restored without overwriting unrelated edits.

A trustworthy header is not an enforcement point

If you later move behind Cloudflare or another proxy, stop this jail before the topology change. Reconstruct identity only from explicitly trusted proxy networks, prevent direct untrusted origin access, remove/overwrite incoming forwarded headers at the trusted edge and verify both original peer and restored address. Never trust X-Forwarded-For from every source or select an arbitrary address in its list. Nginx real_ip_recursive has specific last-nontrusted semantics; it is not header authentication.

For CDN clients, enforcement belongs at a correctly authorized edge API/WAF or a separately designed application-layer decision. Do not put CDN API tokens in tutorial settings, log formats or shell history. This guide does not configure an API action or demonstrate a Cloudflare ban. A spoof-resistant direct-host log does not validate your future proxy trust configuration.

Operate the control as one layer

Review false positives, ban counts, action errors, disk capacity and log rotation. Test reboot/ruleset-manager reload and real packet enforcement only in an authorized isolated network with disposable addresses; none is proved by a status counter. Log loss, clock errors and delayed disk writes can miss decisions. IP bans can be evaded by distributed credential stuffing and can harm shared NAT users. Add application MFA, account-aware throttling, secure passwords, patching and appropriately designed rate limits/WAF. Fail2ban does not stop volumetric DDoS upstream. Minimize log retention, restrict access and remove expired private lab evidence under your own retention policy.

What was checked and what remains yours

OS paths are documentation-reviewed, not five completed installations. The author checks the exact parser, synthetic IPv4/IPv6/negative records and a separate audit-only daemon. This proves local parsing and decisions, not a real client ban, public security, CDN enforcement, service boot, full firewall-manager coexistence, account protection or every OS build. The public settings are untested reader inputs. Generated DEMO studio images illustrate the topic; they are not staff, facilities or test screenshots.

GO TO THE SOURCE

Official references

Each environment states how it was reviewed. A documentation review does not claim a hands-on test of every version.

KEEP LEARNING

Your next step

Explore all tutorials ↗