Initial version of fail2ban-webui

Web interface to view, ban and unban fail2ban IPs on several hosts via
SSH, generalised from the private f2b-web tool.

- Web UI (Flask/Waitress): hosts.yaml, local/OIDC/proxy authentication,
  English/German UI, origin map, optional Loki/Grafana/GeoIP, CLI helpers
- Agent f2b-webctl with install.sh/uninstall.sh (dedicated user + sudo,
  from= restriction, protected networks, manual jail)
- Hardened Docker image, examples, documentation, smoke test, testbed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
schiwagoaandClaude Opus 5.5 committed 2026-10-25 15:38:17 +01:00
commit 2e3f79236c
44 files changed
+4280

No files matched your search

+82
View File
@@ -0,0 +1,82 @@
# =====================================================================
# fail2ban-webui – settings (copy to .env next to docker-compose.yaml)
# Only the block "Authentication" is required, everything else is optional.
# =====================================================================
# ---------------------------------------------------------------------
# General
# ---------------------------------------------------------------------
# External address of the UI (needed for OIDC; also turns on Secure cookies for https)
PUBLIC_URL=https://fail2ban.example.org
# Language when the user has not chosen one in the dropdown (en, de, …)
DEFAULT_LANG=en
# Number of reverse proxies in front of the container whose X-Forwarded-For/-Proto
# headers are trusted (0 = none). Behind one proxy (NPM, Traefik, Caddy): 1
TRUSTED_PROXY_HOPS=1
# Session lifetime in hours
SESSION_HOURS=12
# ---------------------------------------------------------------------
# Authentication – AUTH_MODE: local | oidc | local,oidc | proxy
# ---------------------------------------------------------------------
AUTH_MODE=local
# local: create the hash with
# docker compose run --rm -it fail2ban-webui hash-password
# and paste the printed line (keep the single quotes!)
AUTH_USER=admin
AUTH_PASSWORD_HASH='scrypt:...'
# Lock a client IP after this many failed logins for LOGIN_LOCK_MINUTES
LOGIN_MAX_ATTEMPTS=5
LOGIN_LOCK_MINUTES=15
# oidc: e.g. Authentik – Redirect URI in the provider: ${PUBLIC_URL}/auth/callback
#OIDC_ISSUER=https://auth.example.org/application/o/fail2ban-webui/
#OIDC_CLIENT_ID=
#OIDC_CLIENT_SECRET=
#OIDC_SCOPES=openid email profile
#OIDC_USERNAME_CLAIM=preferred_username
#OIDC_GROUPS_CLAIM=groups
# Strongly recommended: only these groups / users may sign in (comma separated)
#OIDC_ALLOWED_GROUPS=fail2ban-admins
#OIDC_ALLOWED_USERS=
#OIDC_BUTTON_LABEL=Authentik
# proxy: the reverse proxy does the login (forward auth, basic auth, IP list).
# Only requests from these addresses are accepted (address of the proxy):
#AUTH_PROXY_ALLOWED_IPS=172.23.51.1/32
# Header with the user name set by the proxy, e.g. X-authentik-username or Remote-User
#AUTH_PROXY_HEADER=
#AUTH_PROXY_LOGOUT_URL=
# ---------------------------------------------------------------------
# Agents (SSH)
# ---------------------------------------------------------------------
# Default SSH user on the hosts (can be overridden per host in hosts.yaml)
SSH_USER=f2bweb
SSH_TIMEOUT=40
# Seconds the ban list is cached
CACHE_SECONDS=15
# Jail used by the agent for manual bans (only shown in the UI)
MANUAL_JAIL=manual-block
# ---------------------------------------------------------------------
# GeoIP (optional) – country/city per IP
# ---------------------------------------------------------------------
# 1 = download the free DB-IP Lite database (CC BY 4.0) monthly into /data/geoip
GEOIP_AUTO_DOWNLOAD=1
# or mount your own .mmdb (DB-IP or MaxMind GeoLite2 City) and point to it:
#GEOIP_DB=/data/geoip/dbip-city-lite.mmdb
# ---------------------------------------------------------------------
# Loki / Grafana (optional) – "History" button and Grafana links
# ---------------------------------------------------------------------
#LOKI_URL=http://loki:3100
#LOKI_SELECTOR={job=~"fail2ban|sshd|nginx"}
#LOKI_DAYS=7
#LOKI_USER=
#LOKI_PASSWORD=
#LOKI_TENANT=
#GRAFANA_URL=https://grafana.example.org
#GRAFANA_DASHBOARD=/d/my-security-dashboard
#GRAFANA_LOKI_UID=loki
+54
View File
@@ -0,0 +1,54 @@
# =====================================================================
# fail2ban-webui – example docker-compose.yaml
#
# mkdir -p fail2ban-webui/{config,data} && cd fail2ban-webui
# (copy this file, .env.example as .env and hosts.yaml.example as config/hosts.yaml)
# chown -R 10050:10050 data
#
# The UI listens on 127.0.0.1:8080 only – put a reverse proxy with TLS in front of it.
# The network uses its own /24 subnet; change it if it collides with an existing one
# (docker network inspect $(docker network ls -q) | grep Subnet).
# =====================================================================
name: fail2ban-webui
services:
fail2ban-webui:
image: git.retronerd.at/schiwagoa/fail2ban-webui:latest
# build: { context: .., dockerfile: docker/Dockerfile } # build from the repository instead
container_name: fail2ban-webui
restart: unless-stopped
env_file: .env
environment:
TZ: ${TZ:-Europe/Vienna}
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
volumes:
- ./config:/config:ro
- ./data:/data
ports:
- "127.0.0.1:8080:8080"
extra_hosts:
# lets the container reach an agent on the Docker host itself (address: host.docker.internal)
- "host.docker.internal:host-gateway"
deploy:
resources:
limits:
memory: 256M
networks:
fail2ban-webui.dockernetwork.local:
ipv4_address: 172.23.51.10
networks:
fail2ban-webui.dockernetwork.local:
name: fail2ban-webui.dockernetwork.local
driver: bridge
ipam:
config:
- subnet: 172.23.51.0/24
gateway: 172.23.51.1
ip_range: 172.23.51.128/25
+22
View File
@@ -0,0 +1,22 @@
# =====================================================================
# fail2ban-webui – hosts with fail2ban and the agent (copy to config/hosts.yaml)
#
# name shown in the UI (letters, digits, . _ -)
# address DNS name or IP reachable from the container
# port SSH port (default 22)
# user SSH user of the agent (default: SSH_USER from .env, normally f2bweb)
#
# After changes: docker compose run --rm -it fail2ban-webui keyscan
# docker compose restart
# =====================================================================
hosts:
- name: web01
address: web01.example.org
- name: lxc-proxy
address: 192.168.1.20
port: 2222
# fail2ban on the Docker host itself
- name: dockerhost
address: host.docker.internal