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.

Includes NPM. The compose file spins up both Nginx Proxy Manager and the F2B dashboard together. See nginxproxymanager.com for how to configure your proxy hosts.

F2B Control Center — main dashboard

# 1. Pull
git clone https://git.thisisfake.lol/mykey/Fail2Ban-Dashboard---NPM && cd Fail2Ban-Dashboard---NPM

# 2. Open docker-compose.yml — set SUBNETS_TO_IGNORE to your local network ranges

# 3. Run
docker compose up -d

Dashboard at http://YOUR_HOST:4000 — no other setup required.


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:
    modprobe xt_string
    echo xt_string >> /etc/modules   # persist across reboots
    

Quick Start

git clone https://git.thisisfake.lol/mykey/Fail2Ban-Dashboard---NPM
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
Service URL
F2B Dashboard http://YOUR_HOST:4000
NPM Admin UI http://YOUR_HOST:81

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 for a plain-English walkthrough of every dashboard feature.

Filter tabs

Scan results

Live log stream


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.

If this saves you some headaches, you can buy me a coffee: ko-fi.com/manicmedia


FAQ

See FAQ.md for common questions including how to fix Cloudflare IP logging, bans not blocking traffic, and resetting to defaults.


License

MIT — see LICENSE.

Description
No description provided
Readme MIT 844 KiB
Languages
JavaScript 34%
HTML 30.1%
CSS 22.2%
Shell 7.7%
Dockerfile 6%