docs: rewrite README and add user guide

- Full README rewrite: screenshot placeholders, credits, project origin note
- New USERGUIDE.md: plain-English walkthrough for non-technical users
- Documents whitelist vs exempt distinction, all dashboard actions, scan workflow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 18:59:23 +00:00
parent 60bb6abe4f
commit 239e2df8c1
2 changed files with 261 additions and 50 deletions

152
README.md
View File

@@ -1,101 +1,122 @@
# F2B Control Center
Fail2Ban + Nginx Proxy Manager in a single Docker container, with a web dashboard for monitoring and managing bans.
> Fail2Ban management dashboard for Nginx Proxy Manager — bans scanners, bots, and exploit probers automatically, with a browser UI to monitor and control everything.
Pre-built filters detect bad bots, HTTP error spamming, and exploit probing against NPM logs. Bans are enforced via iptables (DOCKER-USER chain + INPUT), with optional Cloudflare WAF banning on top.
<!-- 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 support
- `xt_string` kernel module on the host (`modprobe xt_string`)
- 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://git.thisisfake.lol/mykey/f2b-control-center
git clone https://github.com/YOUR_USERNAME/f2b-control-center
cd f2b-control-center
```
Edit `docker-compose.yml` — at minimum review `SUBNETS_TO_IGNORE`. Then:
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 at `http://YOUR_HOST:4000`
Dashboard is at `http://YOUR_HOST:4000`.
On first start the container installs the default Fail2Ban config into a persistent volume and begins monitoring NPM logs immediately.
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 are in `docker-compose.yml`. Required fields are uncommented. Optional features are commented out — uncomment and fill in to enable.
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 | CIDRs excluded from scanning and banning |
| `ABUSEIPDB_API_KEY` | _(optional)_ | Enables threat scoring and auto-ban |
| `CF_EMAIL` | _(optional)_ | Cloudflare account email — enables WAF banning |
| `CF_APIKEY` | _(optional)_ | Cloudflare Global API Key |
| `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 | Trigger | Ban time |
| Jail | What triggers it | Default ban time |
|---|---|---|
| `badbot` | Known scanner/exploit user-agents | 24h |
| `http-errors` | 15+ 4xx/5xx errors in 5 min | 1h |
| `npm-probe` | Exploit path probing (.env, wp-login, etc.) | 48h |
| `manual-bans` | Manual dashboard or CLI bans | Permanent |
| `recidive` | Repeat offenders (disabled by default) | 7d |
| `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)* |
To customise jails:
```bash
docker exec -it f2b-control-center bash
vi /etc/fail2ban/jail.local
fail2ban-client reload
```
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 uses `network_mode: host` so iptables rules affect the host network stack. Two rules are inserted per ban:
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.
- **DOCKER-USER** — drops forwarded packets where the `X-Forwarded-For` header matches the banned IP (catches traffic routed through Cloudflare/CDN)
- **INPUT** — drops direct connections from the banned IP
Each ban inserts two rules:
Requires `xt_string` on the host:
```bash
modprobe xt_string
# to persist across reboots:
echo xt_string >> /etc/modules
```
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
### Cloudflare WAF (optional)
Uncomment and fill in `CF_EMAIL` and `CF_APIKEY` in `docker-compose.yml`. The container detects these on first start and installs the Cloudflare action alongside iptables — no other changes needed.
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 logs with the real client IP in a `[Client X.X.X.X]` field the format NPM produces when behind Cloudflare or any proxy that forwards `X-Forwarded-For`.
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:
Test a filter against your logs:
```bash
docker exec f2b-control-center \
fail2ban-regex /nginx-logs/proxy-host-1_access.log \
@@ -104,35 +125,66 @@ docker exec f2b-control-center \
---
## Useful Commands
## 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
# View logs
# Stream container logs
docker compose logs -f
# Reload fail2ban config
# 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
```
---
## Volumes
## Credits
| Volume | Path | Contents |
|---|---|---|
| `f2b-data` | `/data` | Ban history database |
| `f2b-config` | `/etc/fail2ban` | Jail and filter config (survives image updates) |
| bind mount | `/nginx-logs` | NPM log directory (read-only) |
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
MIT — see [LICENSE](LICENSE).