From 1be79cbd3e6526f4d338de89d8d1f660bdd0cf07 Mon Sep 17 00:00:00 2001 From: gitea Date: Fri, 20 Feb 2026 15:17:25 +0000 Subject: [PATCH] chore: strip telegram/webhook actions, single compose file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove telegram_notif.sh and all Telegram references - Remove webhook.conf fail2ban action (dashboard webhook stays) - docker-npm.conf: iptables ban/unban only, no lifecycle hooks - Merge docker-compose.cloudflare.yml into docker-compose.yml CF_EMAIL/CF_APIKEY always present — fill in to enable WAF banning - Remove TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID from compose - Drop .env.example dependency — all config inline in compose file Co-Authored-By: Claude Sonnet 4.6 --- Dockerfile | 3 +- docker-compose.cloudflare.yml | 78 ----------------------------- docker-compose.yml | 46 +++++------------ entrypoint.sh | 10 ---- fail2ban/action.d/docker-npm.conf | 17 ++----- fail2ban/action.d/telegram_notif.sh | 54 -------------------- fail2ban/action.d/webhook.conf | 37 -------------- 7 files changed, 17 insertions(+), 228 deletions(-) delete mode 100644 docker-compose.cloudflare.yml delete mode 100644 fail2ban/action.d/telegram_notif.sh delete mode 100644 fail2ban/action.d/webhook.conf diff --git a/Dockerfile b/Dockerfile index 96117d6..1206059 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,8 +43,7 @@ COPY supervisor.conf /etc/supervisor/conf.d/f2b-control-center.conf # ── Startup and health ──────────────────────────────────────────────────────── COPY entrypoint.sh /entrypoint.sh COPY healthcheck.sh /healthcheck.sh -RUN chmod +x /entrypoint.sh /healthcheck.sh \ - /etc/f2b-defaults/action.d/telegram_notif.sh +RUN chmod +x /entrypoint.sh /healthcheck.sh # ── Runtime directories ─────────────────────────────────────────────────────── RUN mkdir -p /data /nginx-logs /var/log /var/run/fail2ban diff --git a/docker-compose.cloudflare.yml b/docker-compose.cloudflare.yml deleted file mode 100644 index 63c70a2..0000000 --- a/docker-compose.cloudflare.yml +++ /dev/null @@ -1,78 +0,0 @@ -# ── F2B Control Center — Cloudflare stack ──────────────────────────────────── -# -# Identical to docker-compose.yml with CF credentials added. -# Bans are enforced at BOTH the iptables level AND the Cloudflare WAF level. -# -# SETUP: -# 1. cp .env.example .env -# 2. Fill in CF_EMAIL and CF_APIKEY in .env -# 3. docker-compose -f docker-compose.cloudflare.yml up -d -# -# On first start the entrypoint detects CF_EMAIL/CF_APIKEY and installs -# jail.cloudflare.local instead of jail.local, enabling the cloudflare -# action for all jails automatically. -# -# IMPORTANT: If you have already started the standard compose and have an -# existing f2b-config volume, delete it first so the CF jail config is -# installed fresh: -# docker-compose down -# docker volume rm f2b-control-center_f2b-config -# docker-compose -f docker-compose.cloudflare.yml up -d -# ───────────────────────────────────────────────────────────────────────────── - -version: "3.9" - -services: - - # ── Nginx Proxy Manager ───────────────────────────────────────────────────── - npm: - image: jc21/nginx-proxy-manager:latest - container_name: nginx-proxy-manager - restart: unless-stopped - ports: - - "80:80" - - "443:443" - - "81:81" - volumes: - - ${DATA_DIR:-./data}/npm:/data - - ${DATA_DIR:-./data}/npm/logs:/data/logs - - ${DATA_DIR:-./data}/letsencrypt:/etc/letsencrypt - - # ── F2B Control Center ────────────────────────────────────────────────────── - f2b-control-center: - build: . - image: f2b-control-center:latest - container_name: f2b-control-center - restart: unless-stopped - depends_on: - - npm - network_mode: host - - environment: - PORT: "${DASHBOARD_PORT:-4000}" - ABUSEIPDB_API_KEY: "${ABUSEIPDB_API_KEY:-}" - SUBNETS_TO_IGNORE: "${SUBNETS_TO_IGNORE:-10.0.0.0/8,172.16.0.0/12,192.168.0.0/16}" - WEBHOOK_URL: "${WEBHOOK_URL:-}" - TELEGRAM_BOT_TOKEN: "${TELEGRAM_BOT_TOKEN:-}" - TELEGRAM_CHAT_ID: "${TELEGRAM_CHAT_ID:-}" - # ── Cloudflare credentials ────────────────────────────────────────────── - # Required: your Cloudflare account email - CF_EMAIL: "${CF_EMAIL}" - # Required: your Cloudflare Global API Key - # https://dash.cloudflare.com/profile/api-tokens → "Global API Key" - CF_APIKEY: "${CF_APIKEY}" - # Internal paths - LOG_DIR: "/nginx-logs" - FAIL2BAN_LOG: "/var/log/fail2ban.log" - JAIL_LOCAL: "/etc/fail2ban/jail.local" - MANUAL_JAIL: "manual-bans" - BAN_HIST_FILE: "/data/ban-history.json" - - volumes: - - ${DATA_DIR:-./data}/npm/logs:/nginx-logs:ro - - f2b-data:/data - - f2b-config:/etc/fail2ban - -volumes: - f2b-data: - f2b-config: diff --git a/docker-compose.yml b/docker-compose.yml index 7982ac9..838f9ec 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,10 @@ -# ── F2B Control Center — standard stack ────────────────────────────────────── -# -# Includes: Nginx Proxy Manager + Fail2Ban + dashboard -# -# QUICK START: -# cp .env.example .env -# # edit .env — at minimum review DATA_DIR and SUBNETS_TO_IGNORE -# docker-compose up -d -# -# CLOUDFLARE: -# To also ban at the CF WAF level, use docker-compose.cloudflare.yml instead. -# ───────────────────────────────────────────────────────────────────────────── +# F2B Control Center — edit values below, then: docker-compose up -d +# Cloudflare WAF banning: fill in CF_EMAIL + CF_APIKEY — activates automatically. version: "3.9" services: - # ── Nginx Proxy Manager ───────────────────────────────────────────────────── npm: image: jc21/nginx-proxy-manager:latest container_name: nginx-proxy-manager @@ -23,13 +12,11 @@ services: ports: - "80:80" - "443:443" - - "81:81" # NPM admin UI (change or restrict in production) + - "81:81" volumes: - - ${DATA_DIR:-./data}/npm:/data - - ${DATA_DIR:-./data}/npm/logs:/data/logs # shared with f2b (see below) - - ${DATA_DIR:-./data}/letsencrypt:/etc/letsencrypt + - ./data/npm:/data + - ./data/letsencrypt:/etc/letsencrypt - # ── F2B Control Center ────────────────────────────────────────────────────── f2b-control-center: build: . image: f2b-control-center:latest @@ -37,31 +24,22 @@ services: restart: unless-stopped depends_on: - npm - - # Host network mode is required so fail2ban's iptables rules affect the - # host network stack — blocking traffic before it reaches NPM containers. network_mode: host - environment: - PORT: "${DASHBOARD_PORT:-4000}" - ABUSEIPDB_API_KEY: "${ABUSEIPDB_API_KEY:-}" - SUBNETS_TO_IGNORE: "${SUBNETS_TO_IGNORE:-10.0.0.0/8,172.16.0.0/12,192.168.0.0/16}" - WEBHOOK_URL: "${WEBHOOK_URL:-}" - TELEGRAM_BOT_TOKEN: "${TELEGRAM_BOT_TOKEN:-}" - TELEGRAM_CHAT_ID: "${TELEGRAM_CHAT_ID:-}" - # Internal paths — only change if you remap volumes + PORT: "4000" + SUBNETS_TO_IGNORE: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" + ABUSEIPDB_API_KEY: "" # optional — enables threat scoring & auto-ban + WEBHOOK_URL: "" # optional — POST on every manual ban + CF_EMAIL: "" # optional — Cloudflare account email (enables WAF banning) + CF_APIKEY: "" # optional — Cloudflare Global API Key LOG_DIR: "/nginx-logs" FAIL2BAN_LOG: "/var/log/fail2ban.log" JAIL_LOCAL: "/etc/fail2ban/jail.local" MANUAL_JAIL: "manual-bans" BAN_HIST_FILE: "/data/ban-history.json" - volumes: - # NPM logs — read-only. Shared with NPM via bind mount above. - - ${DATA_DIR:-./data}/npm/logs:/nginx-logs:ro - # Persistent app state (ban history) + - ./data/npm/logs:/nginx-logs:ro - f2b-data:/data - # Fail2ban config — persists across image updates - f2b-config:/etc/fail2ban volumes: diff --git a/entrypoint.sh b/entrypoint.sh index d30e7e3..1579d12 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -46,16 +46,6 @@ else echo "[f2b-cc] Using existing fail2ban configuration." fi -# ── Deploy telegram_notif.sh to persistent volume (user-editable) ───────────── -mkdir -p /data/action.d -if [ ! -f /data/action.d/telegram_notif.sh ]; then - echo "[f2b-cc] Deploying telegram_notif.sh to /data/action.d/" - cp /etc/f2b-defaults/action.d/telegram_notif.sh /data/action.d/telegram_notif.sh - chmod +x /data/action.d/telegram_notif.sh -else - echo "[f2b-cc] /data/action.d/telegram_notif.sh already present — skipping copy" -fi - # ── Ensure required directories and files exist ─────────────────────────────── mkdir -p /data /var/log /var/run/fail2ban diff --git a/fail2ban/action.d/docker-npm.conf b/fail2ban/action.d/docker-npm.conf index 8148d70..7057fea 100644 --- a/fail2ban/action.d/docker-npm.conf +++ b/fail2ban/action.d/docker-npm.conf @@ -1,21 +1,12 @@ [Definition] -# ── Lifecycle notifications ─────────────────────────────────────────────────── -actionstart = bash /data/action.d/telegram_notif.sh -a start -actionstop = bash /data/action.d/telegram_notif.sh -a stop +# Drops traffic two ways: +# - DOCKER-USER: matches X-Forwarded-For header in forwarded packets (CDN/proxy setups) +# - INPUT: drops direct connections at the host level +# Requires xt_string kernel module on the host (modprobe xt_string). -# ── Ban ─────────────────────────────────────────────────────────────────────── -# 1. DOCKER-USER: drops forwarded packets containing the banned IP in the -# X-Forwarded-For header — catches traffic coming through Cloudflare/CDN -# where the real client IP is forwarded as a header to NPM. -# 2. INPUT: drops direct connections from the banned IP at the host level. -# 3. Telegram notification (silent if TELEGRAM_BOT_TOKEN is unset). actionban = iptables -I DOCKER-USER -m string --algo bm --string 'X-Forwarded-For: ' -j DROP iptables -A INPUT -s -j DROP - bash /data/action.d/telegram_notif.sh -b -r "" -# ── Unban ───────────────────────────────────────────────────────────────────── -# || true prevents failure if the rule was already removed (e.g. on restart). actionunban = iptables -D DOCKER-USER -m string --algo bm --string 'X-Forwarded-For: ' -j DROP || true iptables -D INPUT -s -j DROP || true - bash /data/action.d/telegram_notif.sh -u diff --git a/fail2ban/action.d/telegram_notif.sh b/fail2ban/action.d/telegram_notif.sh deleted file mode 100644 index 12f372e..0000000 --- a/fail2ban/action.d/telegram_notif.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -# ── Telegram notification hook for fail2ban ─────────────────────────────────── -# Called by docker-npm.conf on ban/unban/start/stop events. -# Silently exits if TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID is not set. -# -# Usage: -# telegram_notif.sh -a start|stop -# telegram_notif.sh -b -r "" -# telegram_notif.sh -u -# -# Configure by setting in .env (passed into the container via docker-compose): -# TELEGRAM_BOT_TOKEN=123456:ABC-DEF... -# TELEGRAM_CHAT_ID=-100123456789 -# ───────────────────────────────────────────────────────────────────────────── - -BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}" -CHAT_ID="${TELEGRAM_CHAT_ID:-}" - -# Exit silently if not configured — allows docker-npm action to work without Telegram -[[ -z "$BOT_TOKEN" || -z "$CHAT_ID" ]] && exit 0 - -send() { - curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \ - --data-urlencode "chat_id=${CHAT_ID}" \ - --data-urlencode "text=$1" \ - --data-urlencode "parse_mode=HTML" \ - > /dev/null 2>&1 || true -} - -# Parse flags -ACTION="" BAN_IP="" REASON="" UNBAN_IP="" -while getopts ":a:b:r:u:" opt; do - case $opt in - a) ACTION="$OPTARG" ;; - b) BAN_IP="$OPTARG" ;; - r) REASON="$OPTARG" ;; - u) UNBAN_IP="$OPTARG" ;; - esac -done - -case "$ACTION" in - start) send "🟢 F2B Control Center started" ;; - stop) send "🔴 F2B Control Center stopped" ;; -esac - -if [[ -n "$BAN_IP" ]]; then - MSG="🚫 BANNED: ${BAN_IP}" - [[ -n "$REASON" ]] && MSG="${MSG} [${REASON}]" - send "$MSG" -fi - -if [[ -n "$UNBAN_IP" ]]; then - send "✅ UNBANNED: ${UNBAN_IP}" -fi diff --git a/fail2ban/action.d/webhook.conf b/fail2ban/action.d/webhook.conf deleted file mode 100644 index 72c7a50..0000000 --- a/fail2ban/action.d/webhook.conf +++ /dev/null @@ -1,37 +0,0 @@ -# ── F2B Control Center — webhook action ────────────────────────────────────── -# -# Optional fail2ban action that POSTs a JSON payload to a webhook URL on -# ban and unban events. Useful for Discord, Slack, n8n, or any HTTP endpoint. -# -# USAGE: -# Set WEBHOOK_URL in your .env file. -# Then add to any jail in jail.local: -# -# action = %(action_)s -# webhook[url="%(webhook_url)s"] -# -# And in [DEFAULT]: -# webhook_url = YOUR_WEBHOOK_URL -# -# This action is NOT enabled by default. The dashboard's ban webhook is -# handled separately via the WEBHOOK_URL environment variable in server.js. -# ───────────────────────────────────────────────────────────────────────────── - -[Definition] - -# Variable: webhook URL (set via jail.local or override) -webhook_url = %(url)s - -actionban = curl -s -X POST \ - -H "Content-Type: application/json" \ - -d '{"action":"ban","ip":"","jail":"","failures":,"ts":"'$(date -u +%%Y-%%m-%%dT%%H:%%M:%%SZ)'"}' \ - "%(webhook_url)s" || true - -actionunban = curl -s -X POST \ - -H "Content-Type: application/json" \ - -d '{"action":"unban","ip":"","jail":"","ts":"'$(date -u +%%Y-%%m-%%dT%%H:%%M:%%SZ)'"}' \ - "%(webhook_url)s" || true - -[Init] -name = default -url =