Update the docs and fix some spelling

This commit is contained in:
2026-03-14 21:57:57 +01:00
parent e113294298
commit 31047733e0
11 changed files with 346 additions and 119 deletions

View File

@@ -23,25 +23,24 @@ The project is maintained by Swissmakers GmbH and released under GPL-3.0.
Fail2Ban UI does not replace Fail2Ban. It connects to existing Fail2Ban instances and adds:
- A Dashboard for active jails and recent ban/unban activity with real-time WebSocket updates
- Server Manager for adding new fail2ban servers to Fail2ban-UI
- Central search and unban / ban across jails and servers
- Remote editing / creating, of jail/filter configuration (depending on connector)
- Filter debug integration and live log-pattern testing
- Ban Insights with an interactive 3D threat globe showing blocks per country
- Advanced ban actions for recurring offenders e.g. automatically ban on pfSense, Mikrotik, or OPNsense when threshold is reached
- Data management possibility for permanent block logs and stored ban events
- Configurable alert notifications (Email/SMTP, Webhook, or Elasticsearch) with GeoIP/Whois enrichment and country-based filtering
- Dashboard for active jails and recent ban/unban activity with real-time WebSocket updates
- Server manager for local, SSH, and agent-managed Fail2Ban instances
- Centralized search, ban, and unban operations across jails and servers
- Remote jail/filter configuration management (connector-dependent)
- Filter debug and live log-pattern testing
- Ban insights with an interactive 3D globe by country
- Advanced recurring-offender actions (MikroTik, pfSense, OPNsense)
- Persistent event and permanent-block data management
- Configurable alerts (Email/SMTP, Webhook, Elasticsearch) with GeoIP/Whois enrichment
- Optional OIDC login (Keycloak, Authentik, Pocket-ID)
- Least-privilege, SELinux-aware container deployment (policies provided)
- .. and much more to come.
- Least-privilege, SELinux-aware deployment patterns
## Connector types
| Connector | Typical use | Notes |
|---|---|---|
| Local | Fail2Ban runs on the same host as the UI | Uses the Fail2Ban socket and local files |
| SSH | Manage remote Fail2Ban hosts without installing an agent | Uses key-based SSH, remote `sudo fail2ban-client`, and `sudo systemctl restart fail2ban` (with reload fallback) |
| SSH | Manage remote Fail2Ban hosts without installing an agent | Uses key-based SSH and remote `fail2ban-client` |
| Agent (technical preview) | Environments where SSH is not desired | Limited functionality; work in progress |
## Quick start (container)
@@ -73,6 +72,8 @@ Next steps:
* Installation: [`docs/installation.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/installation.md)
* Configuration reference (env vars, callback URL/secret, OIDC): [`docs/configuration.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/configuration.md)
* Reverse proxy guide: [`docs/reverse-proxy.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/reverse-proxy.md)
* Webhook integration guide: [`docs/webhooks.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/webhooks.md)
* Security guidance (recommended deployment posture): [`docs/security.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/security.md)
* Architecture overview: [`docs/architecture.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/architecture.md)
* API reference: [`docs/api.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/api.md)
@@ -124,7 +125,7 @@ The first button opens the modal for creating new Fail2Ban filter files. Include
#### Create new Jail
![Create Jail](screenshots/1.5_Dashboard_Manage_Jails_Create_Jail.png)
The second button opens the Jail creation modal for setting up new jails. Allows configuration of seperate jails with special parameters, filter selection, with automatic configuration generation.
The second button opens the jail creation modal for setting up new jails. It supports separate jail definitions with custom parameters and filter selection.
### Search Functionality
![Search](screenshots/1.6_Dashboard_search.png)
@@ -176,6 +177,7 @@ Global Fail2Ban settings including default bantime, findtime, maxretry, banactio
* SSH connector should use a dedicated service account with minimal sudo permissions and ACLs (at minimum `sudo fail2ban-client *` and `sudo systemctl restart fail2ban`).
* All IP addresses are validated (strict IPv4/IPv6/CIDR parsing) before being passed to any integration or command, preventing command injection.
* WebSocket connections are protected by origin validation (same-origin only) and require authentication when OIDC is enabled.
* For production proxy examples and WebSocket requirements, see [`docs/reverse-proxy.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/reverse-proxy.md).
See [`docs/security.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/security.md) for details.

View File

@@ -177,7 +177,7 @@ The Fail2Ban UI container requires several volume mounts to function properly. B
- `.ssh/` - Directory for SSH keys used for remote server connections
- Application configuration files
#### `/etc/fail2ban` - Fail2Ban Configuration Directory (reqired for local fail2ban connector only)
#### `/etc/fail2ban` - Fail2Ban configuration directory (required for local connector only)
- **Host Path:** `/etc/fail2ban`
- **Container Path:** `/etc/fail2ban`
- **Purpose:** Access to Fail2Ban configuration files (jails, filters, actions)
@@ -185,7 +185,7 @@ The Fail2Ban UI container requires several volume mounts to function properly. B
- **SELinux Context:** `:Z` flag required on SELinux-enabled systems
- **Note:** Required if managing local Fail2Ban instance
#### `/var/run/fail2ban` - Fail2Ban Socket Directory (reqired for local fail2ban connector only)
#### `/var/run/fail2ban` - Fail2Ban socket directory (required for local connector only)
- **Host Path:** `/var/run/fail2ban`
- **Container Path:** `/var/run/fail2ban`
- **Purpose:** Access to Fail2Ban control socket (`fail2ban.sock`)
@@ -193,10 +193,10 @@ The Fail2Ban UI container requires several volume mounts to function properly. B
- **SELinux Context:** Not required (tmpfs)
- **Note:** Required for local Fail2Ban management
#### `/var/log` - Log Files (reqired for local fail2ban connector only)
#### `/var/log` - Log files (required for local connector only)
- **Host Path:** `/var/log`
- **Container Path:** `/var/log`
- **Purpose:** Read access to system logs for automatically logpath-tests on jail enabe
- **Purpose:** Read access to system logs for automatic logpath tests when enabling jails
- **Permissions:** Read-Only (`:ro`)
- **Note:** If test fails, jail is auto-disabled to prevent fail2ban daemon errors
@@ -204,7 +204,7 @@ The Fail2Ban UI container requires several volume mounts to function properly. B
#### GeoLite2-Country.mmdb - GeoIP Database
- **Host Path:** `/path/to/your/GeoIPFolder`
- **Container Path:** e.g. `/usr/share/GeoIP` paht must match the settings in the UI.
- **Container Path:** e.g. `/usr/share/GeoIP` (path must match the setting in the UI)
- **Purpose:** Only needed if you want to use the MaxMind provider.
- **Permissions:** Read-Only (`:ro`)
- **Note:** Fail2Ban UI uses the built-in ip-api.com by default, which requires no local database
@@ -293,7 +293,7 @@ services:
volumes:
# Required for fail2ban-ui: Stores SQLite database, application settings, and SSH keys of the fail2ban-ui container
- /opt/podman-fail2ban-ui:/config:Z
# Required for fail2ban-ui: Used for testing, that logpath is working, before enabeling a jail. Without this read only access the fail2ban-ui will not be able to enable jails (logpath-test would fail)
# Required for fail2ban-ui: used to validate logpaths before enabling jails
- /var/log:/var/log:ro
# Required for local fail2ban instance: Fail2Ban configuration directory, needed for managing a local Fail2Ban instance (e.g. on host system) via fail2ban-ui

View File

@@ -38,7 +38,7 @@ Click **Send Test Email** in the UI after saving settings. The test email uses t
### Notes
- Office365 and Gmail typically require the `LOGIN` auth method (selected automatically by the `Auto` option).
- Emails include RFC-compliant `Message-ID` and `Date` headers to minimize spam classification. (but can still happen because of the log-content that is sended within a ban-mail.)
- Emails include RFC-compliant `Message-ID` and `Date` headers to improve deliverability.
## Webhook
@@ -91,6 +91,10 @@ The JSON payload will appear as the notification body. For ntfy with authenticat
For Slack or Mattermost incoming webhooks, the endpoint expects a `text` field. Since Fail2Ban UI sends a generic JSON payload, use a middleware or Slack workflow to parse it, or use a webhook-to-Slack bridge.
### Telegram example
Telegram Bot API usually requires payload transformation (`chat_id`, `text`). Use a relay workflow (n8n, Node-RED, custom service) to convert Fail2Ban UI's generic JSON payload into Telegram `sendMessage` format.
### Testing
Click **Send Test Webhook** after saving settings. This sends a test payload (`"event": "test"`) with a dummy IP (`203.0.113.1`) to verify connectivity.
@@ -98,8 +102,8 @@ Click **Send Test Webhook** after saving settings. This sends a test payload (`"
### Technical details
- Timeout: 15 seconds per request.
- The `Content-Type` header is always set to `application/json`.
- Custom headers override any default header except `Content-Type`.
- Default `Content-Type` is `application/json`.
- Custom headers are applied after defaults and can override default headers (including `Content-Type`) if required by the receiver.
- TLS verification can be disabled for self-signed certificates.
- HTTP responses with status >= 400 are treated as errors and logged.
@@ -141,7 +145,7 @@ The raw `fail2ban.logs` and `fail2ban.whois` fields will keep present. Additiona
}
```
**Normalize fields from "fail2ban.logs"** (only present when log was correctly pharsed):
**Normalized fields from `fail2ban.logs`** (only present when log parsing succeeds):
| Field | Type | Description |
|---|---|---|
@@ -167,7 +171,7 @@ The raw `fail2ban.logs` and `fail2ban.whois` fields will keep present. Additiona
| `message` | text | Error message body (error logs) |
| `fail2ban.parsed_logs` | nested | Array of individually parsed log lines (multi-line events) |
**Normalize fields from "fail2ban.whois"** (only present when was correctly pharsed):
**Normalized fields from `fail2ban.whois`** (only present when WHOIS parsing succeeds):
| Field | Type | Description |
|---|---|---|
@@ -183,7 +187,7 @@ The raw `fail2ban.logs` and `fail2ban.whois` fields will keep present. Additiona
| `whois.registration_date` | keyword | Registration date |
| `whois.updated_date` | keyword | Last update date |
**Currently supported log formats** (Sould pharse via grok patterns):
**Currently supported log formats** (parsed via grok patterns):
| Format | Example jail names |
|---|---|
@@ -280,7 +284,7 @@ PUT _index_template/fail2ban
}
```
**Note:** If you already have a `fail2ban` index and index-template from an earlier version, you must update / recreate the inex-template with the new field mappings. Existing documents / inecies are not affected from the change. In Elasticsearch index-templates are only applied on index creation.
**Note:** If you already have an older index template, update/recreate it with the new mappings. Existing indices/documents are not modified retroactively; templates apply when new indices are created.
**2. Create an API key**
@@ -313,7 +317,7 @@ Go to Kibana Discover, select the `fail2ban-events-*` data view, and you should
## Alert dispatch flow
When a ban or unban event arrives via the Fail2Ban callback (and the pharsing was valid):
When a ban or unban event arrives via the Fail2Ban callback (and payload validation succeeds):
1. The event is stored in the database and broadcast via WebSocket (always, regardless of alerts).
2. The system checks whether alerts are enabled for the event type (ban/unban).

View File

@@ -1,129 +1,124 @@
# Configuration reference
This document describes common runtime settings. Some values are stored in the database via the UI; environment variables take precedence where noted.
This document describes common runtime settings and related operational behavior. Most runtime options are configured in the UI and stored in the database. Environment variables override behavior where applicable.
## Network settings
## Network and listener settings
- `PORT`
TCP port for the HTTP server (default: 8080).
HTTP listen port. Default: `8080`.
- `BIND_ADDRESS`
Bind address for the HTTP server (default: `0.0.0.0`). Use `127.0.0.1` if you only publish through a reverse proxy on the same host.
Listen address. Default: `0.0.0.0`.
Recommended with local reverse proxy: `127.0.0.1`.
Example:
```bash
-e PORT=3080 -e BIND_ADDRESS=127.0.0.1
````
```
For production reverse proxy patterns, see [`docs/reverse-proxy.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/reverse-proxy.md).
## Callback URL and secret (Fail2Ban -> UI)
Fail2Ban UI receives ban/unban callbacks at:
* `POST /api/ban`
* `POST /api/unban`
- `POST /api/ban`
- `POST /api/unban`
The callback action on each managed Fail2Ban host must be able to reach the UI callback URL.
Required environment variables:
* `CALLBACK_URL`
The external URL that Fail2Ban hosts use for callbacks.
Default behavior typically matches `http://127.0.0.1:<PORT>` (works for same-host deployments).
- `CALLBACK_URL`
URL reachable from managed Fail2Ban hosts.
- `CALLBACK_SECRET`
Shared secret validated via `X-Callback-Secret` header.
If not set, Fail2Ban UI generates a secret on first start.
* `CALLBACK_SECRET`
Shared secret for authenticating callbacks. If not set, the UI generates one on first start.
Recommended: set a fixed secret in production and keep it private.
Example (container bridge / remote hosts):
Example:
```bash
-e CALLBACK_URL=http://10.88.0.1:3080 \
-e CALLBACK_SECRET='replace-with-a-random-secret'
```
Callbacks must include:
## Privacy and telemetry controls
* Header `X-Callback-Secret: <secret>`
- `DISABLE_EXTERNAL_IP_LOOKUP=true`
Disables external public-IP lookup used in UI display.
- `UPDATE_CHECK=false`
Disables GitHub release update checks.
## Privacy-related settings
## UI behavior flags
* `DISABLE_EXTERNAL_IP_LOOKUP=true`
Disables any external lookup used to display the hosts public IP address in the UI.
- `AUTODARK=false` (default)
Enables automatic dark mode based on browser/OS preference only when `true`.
Default behavior remains light mode.
* `UPDATE_CHECK=false`
Disables checking GitHub for a newer release.
## Fail2Ban configuration migration
## Fail2Ban config migration
- `JAIL_AUTOMIGRATION=true`
EXPERIMENTAL migration from monolithic `jail.local` to `jail.d/*.local`.
Recommended: migrage manually on production systems.
* `JAIL_AUTOMIGRATION=true`
Experimental: attempts to migrate a monolithic `jail.local` into `jail.d/`.
Recommended: migrate manually on production systems.
## Alert settings (UI-managed)
## Email template selection
Configure in **Settings -> Alert Settings**:
* `emailStyle=classic`
Switches back alert emails from the modern template to the classic template (only applies when the Email alert provider is selected).
- Provider: `email` | `webhook` | `elasticsearch`
- Enable alerts for bans/unbans
- Alert country filters
- GeoIP provider and log-line limits
## Alert providers
Detailed provider behavior and payloads:
Alert settings are configured through the UI (Settings → Alert Settings). Three providers are available:
- [`docs/alert-providers.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/alert-providers.md)
- [`docs/webhooks.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/webhooks.md)
| Provider | Description |
|---|---|
| Email (SMTP) | Default. Sends HTML-formatted alert emails via SMTP. |
| Webhook | Sends JSON payloads to any HTTP endpoint (ntfy, Matrix, Slack, Gotify, custom APIs). |
| Elasticsearch | Indexes events as ECS-compatible documents into Elasticsearch for Kibana analysis. |
## Threat intelligence settings (UI-managed)
All providers share the same global settings:
- Enable/disable alerts for bans and unbans independently
- Country-based alert filtering (only alert on selected countries)
- GeoIP provider selection (built-in API or local MaxMind database)
- Maximum log lines included in alert payloads
Provider-specific settings (SMTP credentials, webhook URL/headers, Elasticsearch URL/auth) are configured in the same UI section and stored in the database.
For full provider documentation, setup hints, payload formats, and examples, see [`docs/alert-providers.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/alert-providers.md).
## Threat intelligence
Threat intelligence settings are configured through the UI (Settings -> Alert Settings):
Configure in **Settings -> Alert Settings**:
- `threatIntel.provider`: `none` | `alienvault` | `abuseipdb`
- `threatIntel.alienVaultApiKey`: required when provider is `alienvault`
- `threatIntel.abuseIpDbApiKey`: required when provider is `abuseipdb`
- `threatIntel.alienVaultApiKey` (for `alienvault`)
- `threatIntel.abuseIpDbApiKey` (for `abuseipdb`)
Runtime behavior:
- Lookups are performed through the backend endpoint `GET /api/threat-intel/:ip`.
- Successful results are cached per provider+IP for 30 minutes. (currently in-memory only -> if a modal is reopened multible times..)
- Upstream 429 responses trigger retry-window handling and stale-cache fallback (if available).
Runtime notes:
For full details (setup, response model, cache/rate-limit behavior, and troubleshooting), see [`docs/threat-intel.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/threat-intel.md).
- Queries are executed server-side via `GET /api/threat-intel/:ip`
- Successful responses are cached for 30 minutes (provider+IP)
- Upstream `429` triggers retry-window/backoff with stale-cache fallback
See [`docs/threat-intel.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/threat-intel.md) for full details.
## OIDC authentication
OIDC can protect the UI with an external identity provider.
Required when enabled:
Required:
- `OIDC_ENABLED=true`
- `OIDC_PROVIDER=keycloak|authentik|pocketid`
- `OIDC_ISSUER_URL=...`
- `OIDC_CLIENT_ID=...`
- `OIDC_CLIENT_SECRET=...`
- `OIDC_REDIRECT_URL=https://<ui-host>/auth/callback`
* `OIDC_ENABLED=true`
* `OIDC_PROVIDER=keycloak|authentik|pocketid`
* `OIDC_ISSUER_URL=...`
* `OIDC_CLIENT_ID=...`
* `OIDC_CLIENT_SECRET=...`
* `OIDC_REDIRECT_URL=https://<ui-host>/auth/callback`
Common optional variables:
Optional (common):
* `OIDC_SCOPES=openid,profile,email`
* `OIDC_SESSION_SECRET=<32+ bytes recommended>` (random is generated if omitted)
* `OIDC_SESSION_MAX_AGE=3600`
* `OIDC_USERNAME_CLAIM=preferred_username`
* `OIDC_SKIP_VERIFY=false` (development only)
* `OIDC_SKIP_LOGINPAGE=false`
- `OIDC_SCOPES=openid,profile,email`
- `OIDC_SESSION_SECRET=<32+ bytes recommended>`
- `OIDC_SESSION_MAX_AGE=3600`
- `OIDC_USERNAME_CLAIM=preferred_username`
- `OIDC_SKIP_VERIFY=false` (development only)
- `OIDC_SKIP_LOGINPAGE=false`
Provider notes:
* Keycloak: ensure your client allows the redirect URI (`/auth/callback`) and post-logout redirect (`/auth/login`).
* Authentik/Pocket-ID: follow their OIDC client configuration and match the redirect URI exactly.
- Keycloak: allow redirect URI `/auth/callback` and post-logout redirect `/auth/login`
- Authentik/Pocket-ID: redirect URI must match exactly
Additional resources:
Related:
* OIDC dev environment: `development/oidc/README.md`
- OIDC dev stack: `development/oidc/README.md`
## Email template style
- `emailStyle=classic`
Uses the classic email template instead of the default modern template (Email provider only).

View File

@@ -2,8 +2,6 @@
This document provides a short installation path and points to the full deployment guides in the repository.
Spoiler: They need to be reworked as well we already did with the main files here..
## Supported platforms
Fail2Ban UI targets Linux hosts. Typical environments include RHEL/Rocky/Alma, Debian/Ubuntu, and container environments in general.
@@ -44,7 +42,8 @@ cp docker-compose-allinone.example.yml docker-compose.yml
podman compose up -d
```
You can also start and test the full dev-stacks from the development folders, it you only want to try it out.
You can also run the development stacks under `development/` if you want to evaluate features first.
### Option C: Build the image yourself
@@ -75,9 +74,19 @@ cd /opt/fail2ban-ui
# Build static CSS assets
./build-tailwind.sh
# Build the go-binery
# Build the Go binary
go build -o fail2ban-ui ./cmd/server/main.go
```
Then follow `deployment/systemd/README.md` to install the unit file and configure permissions.
## Production recommendation
For production deployments:
- Enable OIDC if your environment supports centralized identity.
- Keep the UI behind a reverse proxy (TLS termination + access controls).
- Bind the UI to loopback (`BIND_ADDRESS=127.0.0.1`) when proxy and app share the host.
Reference: [`docs/reverse-proxy.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/reverse-proxy.md).

122
docs/reverse-proxy.md Normal file
View File

@@ -0,0 +1,122 @@
# Reverse Proxy Deployment Guide
This guide provides production-redy guidance for running Fail2Ban UI behind a reverse proxy.
## Why this matters
Fail2Ban UI includes administrative capabilities and callback endpoints. A reverse proxy lets you apply TLS, access controls, and standardized HTTP security policies before traffic reaches the UI.
## Basic architecture
```text
Browser / Fail2Ban hosts
|
HTTPS (443)
|
Reverse Proxy (TLS termination)
|
HTTP (127.0.0.1:8080)
|
Fail2Ban UI
```
Recommended runtime settings for the above example:
- `BIND_ADDRESS=127.0.0.1` (when proxy and UI run on the same host)
- `PORT=8080` (or another local port)
- `OIDC_ENABLED=true` for user authentication (optional but recommended)
## Reverse proxy requirements
For correct UI behavior (including WebSocket live updates), the proxy must:
1. Preserve `Host` and `Origin` consistency.
2. Allow WebSocket upgrades on `GET /api/ws`.
3. Forward client IP context (`X-Forwarded-For`, `X-Forwarded-Proto`).
## Nginx reference configuration
Use this as a baseline and adapt to your hostnames and certificates.
```nginx
server {
listen 80;
server_name fail2ban.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name fail2ban.example.com;
ssl_certificate /etc/letsencrypt/live/fail2ban.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/fail2ban.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
# Optional strict transport security (don't forget to preload via -> https://hstspreload.org/)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header Referrer-Policy no-referrer always;
# Optional source allowlist
# allow 10.0.0.0/8;
# allow 192.168.0.0/16;
# deny all;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
# Proxy WebSocket endpoint
location /api/ws {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
```
## Caddy reference configuration
```caddy
fail2ban.example.com {
encode zstd gzip
header {
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "no-referrer"
}
reverse_proxy 127.0.0.1:8080
}
```
Caddy automatically handles TLS and WebSocket upgrades for this basic setup.
## Validation checklist / some tests
1. Validate UI: `curl -Ik https://fail2ban.example.com/`
2. Validate API reachability: `curl -s https://fail2ban.example.com/api/version`
3. Validate WebSocket in browser dev tools:
- status `101 Switching Protocols` for `/api/ws`
- live ban/unban events update without refresh
4. Validate callback path from managed Fail2Ban hosts to configured `CALLBACK_URL`

View File

@@ -12,6 +12,8 @@ This project can perform security-sensitive operations (bans, configuration chan
If you must publish it, put it behind TLS and an authentication layer, and restrict source IPs.
See [`docs/reverse-proxy.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/reverse-proxy.md) for hardened proxy examples and WebSocket forwarding requirements.
## Input validation
All user-supplied IP addresses are validated using Go's `net.ParseIP` and `net.ParseCIDR` before they are passed to any integration, command, or database query. This applies to:
@@ -32,10 +34,10 @@ The WebSocket endpoint (`/api/ws`) is protected by:
## Callback endpoint protection
The fail2ban callback endpoints (`/api/ban`, `/api/unban`) are only reachable with a correct `CALLBACK_SECRET`. This secret must be atleast 20 characters long. If not specified a secure secret, will be automatically genereated on first start. It can be further protected by:
The callback endpoints (`/api/ban`, `/api/unban`) are protected by `CALLBACK_SECRET` (`X-Callback-Secret` header). If no secret is specified, Fail2Ban UI generates one on first start. Additional hardening:
- Use even a stronger `CALLBACK_SECRET` than our default (32 characters)
- Make network restrictions (only allow known Fail2Ban hosts to reach the callback endpoint)
- Use a long, random secret and rotate it on suspected leakage
- Restrict network access so only known Fail2Ban hosts can reach callback endpoints
Rotate the secret if you suspect leakage.
@@ -45,7 +47,7 @@ For SSH-managed hosts:
- Use a dedicated service account (not a human user).
- Require key-based auth.
- Restrict sudo to the minimum set of commands required to operate Fail2Ban (at minimum `fail2ban-client *` and `systemctl restart fail2ban`.
- Restrict sudo to the minimum set of commands required to operate Fail2Ban (at minimum `fail2ban-client *` and `systemctl restart fail2ban`).
- Use filesystem ACLs for `/etc/fail2ban` rather than broad permissions to allow full modification capabilities for the specific user.
## Integration connector hardening
@@ -67,7 +69,7 @@ Avoid running with more privileges than necessary. If you run in a container, us
## SELinux
If SELinux is enabled, use the policies provided in (according to your specific setup they are not enough):
If SELinux is enabled, use the policies provided in:
- `deployment/container/SELinux/`
Do not disable SELinux as a shortcut. Fix always labeling and policy issues instead. -> Everytime you read "to disable SELinux" you can close that guide :)
@@ -78,7 +80,7 @@ Fail2Ban UI supports three alert providers: Email (SMTP), Webhook, and Elasticse
### Email (SMTP)
- Use TLS (`Use TLS` enabled) for all SMTP connections to maximize security here.
- Use TLS (`Use TLS` enabled) for all SMTP connections.
- Avoid disabling TLS verification (`Skip TLS Verification`) in production. If you must, ensure the network path to the SMTP server is trusted.
- Use application-specific passwords or OAuth tokens where supported (e.g. Gmail, Office365) instead of primary account passwords.

View File

@@ -26,7 +26,7 @@ This feature is optional and is disabled by default.
Go to **Settings -> Alert Settings**:
1. (If your have no API key jet, register a fresh one now)
1. If you do not have an API key yet, create one with your selected provider.
2. Set **Threat Intel Provider** to `AlienVault OTX` or `AbuseIPDB`.
3. Enter the matching API key.
4. Save settings.

View File

@@ -39,7 +39,7 @@ systemctl status fail2ban
ls -la /var/run/fail2ban/fail2ban.sock
fail2ban-client status
# check the socked in the container:
# check the socket in the container:
podman exec -it fail2ban-ui ls -la /var/run/fail2ban/fail2ban.sock
# SELinux check for alerts (needs "setroubleshoot" linux package):
@@ -403,4 +403,22 @@ Example:
```bash
ls -la /opt/fail2ban-ui
sqlite3 /opt/fail2ban-ui/fail2ban-ui.db "PRAGMA integrity_check;"
sqlite3 /opt/fail2ban-ui/fail2ban-ui.db "PRAGMA integrity_check;"
```
Expected output:
- `ok` -> database is healthy
- Any other output -> investigate filesystem errors and restore from backup if needed
## Reverse proxy checks
If the UI loads but real-time updates fail:
- Verify proxy forwards WebSocket upgrades to `/api/ws`
- Ensure proxy preserves `Host` and does not create `Origin`/`Host` mismatches
- Confirm TLS termination and backend route target are correct
Reference configurations:
- [`docs/reverse-proxy.md`](https://github.com/swissmakers/fail2ban-ui/blob/main/docs/reverse-proxy.md)

75
docs/webhooks.md Normal file
View File

@@ -0,0 +1,75 @@
# Webhook Integration Guide
This guide covers webhook behavior in Fail2Ban UI and provides practical integration patterns.
## Webhook integration model
Fail2Ban UI sends a generic JSON payload. Some platforms accept it directly; others require a transformer/relay.
Example payload:
```json
{
"event": "ban",
"ip": "203.0.113.42",
"jail": "sshd",
"hostname": "edge-01",
"country": "DE",
"failures": "5",
"whois": "...",
"logs": "...",
"timestamp": "2026-03-14T11:45:00Z"
}
```
## Direct webhook examples
### ntfy
- Webhook URL: `https://ntfy.example.com/fail2ban-alerts`
- Method: `POST`
- Optional headers:
- `Title: Fail2Ban Alert`
- `Priority: high`
- `Tags: rotating_light`
- `Authorization: Bearer <token>` (if protected)
### Generic internal endpoint
- Webhook URL: `https://alerts.internal.example/api/fail2ban`
- Method: `POST`
- Header example: `Authorization: Bearer <service-token>`
## Relay integration (example for e.g. Telegram)
If a API does not natively consume the generic Fail2Ban UI payload format as-is; for example the Telegram Bot, you need to use a relay/automation layer (for example n8n, Node-RED, Make, or a small custom service).
### Example Option 1 -> n8n flow (recommended)
1. In Fail2Ban UI, set webhook URL to your n8n webhook endpoint.
2. In n8n:
- Trigger: Webhook node (receives Fail2Ban payload)
- Transform: Set/Function node to build message text
- Action: Telegram node (`sendMessage`) using bot token and chat ID
Example message template:
```text
[Fail2Ban] {{$json.event | upperCase}}
IP: {{$json.ip}}
Jail: {{$json.jail}}
Host: {{$json.hostname}}
Country: {{$json.country}}
Time: {{$json.timestamp}}
```
### Example Option 2 -> minimal relay service
Build a small HTTP service that:
1. Accepts Fail2Ban UI payload.
2. Formats a concise text message.
3. Calls `https://api.telegram.org/bot<TOKEN>/sendMessage` with `chat_id` and `text`.
This approach is also suitable for Slack, Mattermost, Teams, and Discord transformations.

View File

@@ -32,7 +32,7 @@ This directory contains screenshots showcasing the features and the interface of
### Create Jail
![Create Jail](1.5_Dashboard_Manage_Jails_Create_Jail.png)
**Description:** The second button opens the Jail creation modal for setting up new jails. Allows configuration of seperate jails with special parameters, filter selection, with automatic configuration generation.
**Description:** The second button opens the jail creation modal for setting up new jails. It supports separate jail definitions with custom parameters and filter selection.
## Search Functionality
![Search](1.6_Dashboard_search.png)