mirror of
https://github.com/swissmakers/fail2ban-ui.git
synced 2026-03-21 17:13:26 +01:00
Update the docs and fix some spelling
This commit is contained in:
28
README.md
28
README.md
@@ -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
|
||||

|
||||
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
|
||||

|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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 host’s 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).
|
||||
@@ -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
122
docs/reverse-proxy.md
Normal 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`
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
75
docs/webhooks.md
Normal 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.
|
||||
@@ -32,7 +32,7 @@ This directory contains screenshots showcasing the features and the interface of
|
||||
|
||||
### Create Jail
|
||||

|
||||
**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
|
||||

|
||||
|
||||
Reference in New Issue
Block a user