Initial release: F2B Control Center v1.0

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)
This commit is contained in:
2026-02-20 18:59:56 +00:00
commit c104e27506
24 changed files with 3333 additions and 0 deletions

190
README.md Normal file
View File

@@ -0,0 +1,190 @@
# 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.
<!-- SCREENSHOT: Main dashboard — full grid of ban cards visible, mix of BADBOT/NPM-PROBE/HTTP-ERRORS jail badges, AbuseIPDB scores showing on several cards, dark terminal UI -->
---
## 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.
<!-- SCREENSHOT: Filter tab row — all tab buttons visible ([ALL][BADBOT][NPM][HTTP-ERRORS][PRISON][WHITELIST][EXEMPT][SCAN]), one tab active/highlighted -->
<!-- SCREENSHOT: Scan results panel — several suspect IP cards visible with [BAN], [EXEMPT], [THREAT], [RECORDS] buttons; one card showing an AbuseIPDB score -->
<!-- SCREENSHOT: Live log stream — scrolling fail2ban log output showing ban events in real time, terminal-style -->
---
## 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).