# 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, `.env` files, 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_string` kernel module loaded on the host: ```bash modprobe xt_string echo xt_string >> /etc/modules # persist across reboots ``` --- ## Quick Start ```bash 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. ```bash 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: 1. **DOCKER-USER chain** — drops forwarded traffic where the `X-Forwarded-For` header matches the banned IP. Catches traffic routed through Cloudflare or other CDNs. 2. **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](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: ```bash 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 ```bash # 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](https://github.com/fail2ban/fail2ban) | IP ban engine and jail framework | | [Nginx Proxy Manager](https://nginxproxymanager.com) — jc21 | The reverse proxy this was designed for | | [AbuseIPDB](https://www.abuseipdb.com) | Threat intelligence API and reporting | | [Express.js](https://expressjs.com) | Dashboard API server | | [ipaddr.js](https://github.com/whitequark/ipaddr.js) | IP and CIDR address parsing | | [VT323](https://fonts.google.com/specimen/VT323) | Retro terminal UI font (Google Fonts) | | [supervisord](http://supervisord.org) | Multi-process management inside the container | | [Docker](https://www.docker.com) | 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](https://claude.ai) (Anthropic). If you're curious what AI-assisted development looks like in practice, this project is a fairly honest example. --- ## License MIT — see [LICENSE](LICENSE).