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:
152
README.md
152
README.md
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user