Fail2Ban + Nginx Proxy Manager dashboard in a single Docker container. Features: - Auto-ban via badbot, http-errors, npm-probe, manual-bans, recidive jails - Web dashboard: live ban grid, log scanner, per-IP access log viewer - iptables-nft banning (DOCKER-USER + INPUT chains) - Optional Cloudflare WAF banning - Optional AbuseIPDB threat scoring - Two-tier IP management: whitelist (trusted) vs exempt (reviewed) - Auto log-file detection via logwatch (no restart needed for new NPM hosts)
F2B Control Center
Fail2Ban management dashboard for Nginx Proxy Manager — bans scanners, bots, and exploit probers automatically, with a browser UI to monitor and control everything.
What It Does
F2B Control Center runs alongside Nginx Proxy Manager as a single Docker container. It watches your NPM access logs in real time and automatically bans IPs that are:
- Using known scanner or hacking-tool user-agents (masscan, sqlmap, zgrab, etc.)
- Probing for common exploits — WordPress logins,
.envfiles, admin panels, PHP shells - Hammering your services with repeated HTTP errors
Bans are enforced at the iptables level — blocked IPs can't reach anything on the host, not just one service. Optionally, bans also push to Cloudflare WAF to block traffic before it even hits your server.
The dashboard gives you a live view of every active ban, lets you manually ban/unban IPs, scan logs for suspicious activity, check threat reputation via AbuseIPDB, and manage your trusted IP whitelist — all from the browser.
Requirements
- Docker + Docker Compose
- Linux host with iptables/nftables support
- Nginx Proxy Manager (or any reverse proxy writing NPM-format access logs)
xt_stringkernel module loaded on the host:modprobe xt_string echo xt_string >> /etc/modules # persist across reboots
Quick Start
git clone https://github.com/YOUR_USERNAME/f2b-control-center
cd f2b-control-center
Open docker-compose.yml and set SUBNETS_TO_IGNORE to your local network ranges — these IPs will never be scanned or banned. Everything else works out of the box.
docker compose up -d
Dashboard is at http://YOUR_HOST:4000.
On first start the container populates a persistent config volume from the bundled defaults and begins monitoring NPM logs immediately. No manual fail2ban setup required.
Configuration
All settings live in docker-compose.yml. Required fields are uncommented. Optional integrations are commented out — uncomment and fill in to enable them.
| Variable | Default | Description |
|---|---|---|
PORT |
4000 |
Dashboard port |
SUBNETS_TO_IGNORE |
RFC1918 ranges | Comma-separated CIDRs excluded from scanning and banning |
ABUSEIPDB_API_KEY |
(optional) | Enables AbuseIPDB threat scores and report submission |
CF_EMAIL |
(optional) | Cloudflare account email — enables WAF banning |
CF_APIKEY |
(optional) | Cloudflare Global API Key |
Jails
| Jail | What triggers it | Default ban time |
|---|---|---|
badbot |
Known scanner/exploit user-agents | 24 hours |
http-errors |
15+ 4xx/5xx errors in 5 minutes | 1 hour |
npm-probe |
Exploit path probing (.env, wp-login, admin panels, etc.) | 48 hours |
manual-bans |
Manually banned via dashboard or CLI | Permanent |
recidive |
Repeat offenders — 3 bans within 24h | 7 days (disabled by default) |
Jail thresholds (ban time, retry count, window) are tunable in the fail2ban/jail.local config, which persists in the f2b-config Docker volume across image updates. You can also edit it live through the dashboard's Jail Manager.
How Banning Works
The container runs with network_mode: host and NET_ADMIN/NET_RAW capabilities so it can write iptables rules directly on the host network stack.
Each ban inserts two rules:
- DOCKER-USER chain — drops forwarded traffic where the
X-Forwarded-Forheader matches the banned IP. Catches traffic routed through Cloudflare or other CDNs. - INPUT chain — drops direct connections from the banned IP.
Bans survive container restarts (fail2ban reloads its state from disk). They do not survive host reboots unless you also enable the recidive jail or use persistent iptables (e.g., iptables-persistent).
Cloudflare WAF (optional)
Uncomment CF_EMAIL and CF_APIKEY in docker-compose.yml. The container detects these on startup and activates Cloudflare banning automatically — no other config needed. Every ban also creates a Cloudflare firewall rule, blocking the IP at the edge before it reaches your server.
Get your Global API Key at: https://dash.cloudflare.com/profile/api-tokens
Dashboard
See USERGUIDE.md for a plain-English walkthrough of every dashboard feature.
Log Format
Filters expect NPM access logs with the real client IP in a [Client X.X.X.X] field. This is the format NPM produces when sitting behind Cloudflare or any proxy that forwards X-Forwarded-For.
To verify your filters are working:
docker exec f2b-control-center \
fail2ban-regex /nginx-logs/proxy-host-1_access.log \
/etc/fail2ban/filter.d/http-errors.conf
Volumes
| Volume | Container path | Contents |
|---|---|---|
f2b-data |
/data |
Ban history, exemptions list |
f2b-config |
/etc/fail2ban |
Jail and filter config (persists across image rebuilds) |
| bind mount | /nginx-logs |
NPM log directory (read-only) |
To reset config to defaults: docker volume rm f2b-control-center_f2b-config then restart.
CLI Reference
# Stream container logs
docker compose logs -f
# Reload fail2ban after manual config edits
docker exec f2b-control-center fail2ban-client reload
# Check jail status
docker exec f2b-control-center fail2ban-client status
docker exec f2b-control-center fail2ban-client status badbot
# Manual ban / unban
docker exec f2b-control-center fail2ban-client set manual-bans banip 1.2.3.4
docker exec f2b-control-center fail2ban-client set manual-bans unbanip 1.2.3.4
# Test a filter against your logs
docker exec f2b-control-center \
fail2ban-regex /nginx-logs/proxy-host-1_access.log \
/etc/fail2ban/filter.d/npm-probe.conf
Credits
This project is built on and integrates the following open-source tools and services:
| Fail2Ban | IP ban engine and jail framework |
| Nginx Proxy Manager — jc21 | The reverse proxy this was designed for |
| AbuseIPDB | Threat intelligence API and reporting |
| Express.js | Dashboard API server |
| ipaddr.js | IP and CIDR address parsing |
| VT323 | Retro terminal UI font (Google Fonts) |
| supervisord | Multi-process management inside the container |
| Docker | Container runtime |
About This Project
This started as a personal setup I built to protect my own self-hosted services. The filters, iptables actions, and log parsing logic came out of real-world use on my own infrastructure.
The migration from personal scripts into a clean, shareable Docker project — packaging, entrypoint initialization, the dashboard UI, and this documentation — was done with significant help from Claude (Anthropic). If you're curious what AI-assisted development looks like in practice, this project is a fairly honest example.
License
MIT — see LICENSE.