Files
fail2ban-webui/docs/configuration.md
T
schiwagoaandClaude Opus 5.5 2e3f79236c 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>
2026-10-25 15:38:17 +01:00

125 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Configuration
The web UI is configured with environment variables (`.env`, loaded via `env_file:`) and
the host list `config/hosts.yaml`. A complete, commented template is
[`examples/.env.example`](../examples/.env.example). Changes need
`docker compose up -d` (which recreates the container).
Values containing `$` (password hashes, some secrets) must be wrapped in **single quotes**
in `.env`, otherwise Docker Compose expands them.
## Hosts – config/hosts.yaml
```yaml
hosts:
- name: web01 # shown in the UI: letters, digits, . _ -
address: web01.example.org # DNS name or IP, reachable from the container
port: 22 # optional, default 22
user: f2bweb # optional, default SSH_USER
```
After adding a host run `keyscan` again, then restart:
```bash
docker compose run --rm -it fail2ban-webui keyscan
docker compose run --rm fail2ban-webui check
docker compose up -d --force-recreate
```
`F2B_HOSTS=name=address,name2=address2` (port 22, user `SSH_USER`) is still accepted for
compatibility; entries from both are combined.
## General
| Variable | Default | Meaning |
|---|---|---|
| `PUBLIC_URL` | – | external URL, e.g. `https://fail2ban.example.org`. Required for OIDC; with `https://` session cookies get the `Secure` flag |
| `DEFAULT_LANG` | `en` | language until a user picks one in the dropdown (`en`, `de`, …) |
| `TRUSTED_PROXY_HOPS` | `0` | number of reverse proxies whose `X-Forwarded-For`/`-Proto` headers are trusted. Behind one proxy: `1`. Wrong values make the audit log and the login lockout use the wrong client IP |
| `SESSION_HOURS` | `12` | session lifetime |
| `SESSION_COOKIE_SECURE` | from `PUBLIC_URL` | force the `Secure` cookie flag on/off |
| `SECRET_KEY` | generated | key that signs session cookies; by default created once in `data/secret_key` |
| `TZ` | `Europe/Vienna` (compose) | time zone of the log and audit timestamps |
| `CONFIG_FILE` | `/config/hosts.yaml` | path of the host list inside the container |
| `DATA_DIR` | `/data` | data directory inside the container |
## Authentication
See [authentication.md](authentication.md) for the complete setup.
| Variable | Default | Meaning |
|---|---|---|
| `AUTH_MODE` | `local` | `local`, `oidc`, `local,oidc` or `proxy` |
| `AUTH_USER` | `admin` | local user name |
| `AUTH_PASSWORD_HASH` | – | scrypt hash from `hash-password` (single quotes!) |
| `AUTH_PASSWORD_HASH_FILE` | – | alternative: file containing the hash (e.g. a Docker secret) |
| `LOGIN_MAX_ATTEMPTS` | `5` | failed logins per client IP before the lockout |
| `LOGIN_LOCK_MINUTES` | `15` | duration of the lockout window |
| `OIDC_ISSUER` | – | issuer URL; the discovery document is read from `<issuer>/.well-known/openid-configuration` |
| `OIDC_DISCOVERY_URL` | – | full discovery URL instead of `OIDC_ISSUER` |
| `OIDC_CLIENT_ID` / `OIDC_CLIENT_SECRET` | – | client credentials |
| `OIDC_SCOPES` | `openid email profile` | requested scopes |
| `OIDC_USERNAME_CLAIM` | `preferred_username` | claim shown as user name (falls back to `email`, then `sub`) |
| `OIDC_GROUPS_CLAIM` | `groups` | claim with the group list |
| `OIDC_ALLOWED_GROUPS` | – | only members of these groups may sign in (comma separated) |
| `OIDC_ALLOWED_USERS` | – | only these user names may sign in |
| `OIDC_BUTTON_LABEL` | `SSO` | text on the login button ("Sign in with …") |
| `AUTH_PROXY_ALLOWED_IPS` | – | proxy mode: only accept requests from these addresses/networks |
| `AUTH_PROXY_HEADER` | – | proxy mode: header with the user name, e.g. `X-authentik-username` |
| `AUTH_PROXY_LOGOUT_URL` | – | proxy mode: target of the "Sign out" button |
## Agents (SSH)
| Variable | Default | Meaning |
|---|---|---|
| `SSH_USER` | `f2bweb` | default user for hosts without `user:` |
| `SSH_KEY` | `/data/ssh/id_ed25519` | private key |
| `KNOWN_HOSTS` | `/data/ssh/known_hosts` | pinned host keys (written by `keyscan`) |
| `SSH_TIMEOUT` | `40` | seconds per agent call |
| `CACHE_SECONDS` | `15` | how long the ban list is cached between page refreshes |
| `MANUAL_JAIL` | `manual-block` | jail name shown in the UI hint – the agent decides the real jail (`/etc/f2b-webctl.conf`) |
| `AUDIT_LOG` | `/data/audit.log` | audit log (JSON lines) |
The SSH client ignores the system `ssh_config`, uses only the configured key, never
asks questions and refuses unknown host keys.
## GeoIP
| Variable | Default | Meaning |
|---|---|---|
| `GEOIP_AUTO_DOWNLOAD` | `0` | `1`: download the free [DB-IP Lite](https://db-ip.com/db/lite.php) city database (CC BY 4.0) and refresh it monthly |
| `GEOIP_DB` | `/data/geoip/dbip-city-lite.mmdb` | path of the database – any MaxMind-format city database works (e.g. GeoLite2 City) |
With a city database the UI also shows the **origin map** (country-only databases have no
coordinates). The map is bundled with the app (Natural Earth, public domain) – no external
tile server is contacted. Without a database the "Origin" column stays empty and the map
is hidden.
## Loki and Grafana
With Loki the UI gets a **History** button per IP showing the matching log lines of the
last days; with Grafana every ban gets a link to Explore.
| Variable | Default | Meaning |
|---|---|---|
| `LOKI_URL` | – | e.g. `http://loki:3100`; empty = history disabled |
| `LOKI_SELECTOR` | `{job=~".+"}` | LogQL stream selector for the search, e.g. `{job=~"fail2ban\|sshd\|nginx"}` |
| `LOKI_DAYS` | `7` | how far back to search |
| `LOKI_LIMIT` | `50` | maximum lines |
| `LOKI_USER` / `LOKI_PASSWORD` | – | basic auth |
| `LOKI_TENANT` | – | `X-Scope-OrgID` for multi-tenant Loki |
| `GRAFANA_URL` | – | e.g. `https://grafana.example.org` |
| `GRAFANA_DASHBOARD` | – | path of a dashboard for the header link, e.g. `/d/abc123/security` |
| `GRAFANA_LOKI_UID` | `loki` | UID of the Loki data source in Grafana (for Explore links) |
Example – exclude the UI's own access log from the search:
```ini
LOKI_SELECTOR={job=~"fail2ban|ufw|nginx|sshd", domain!="fail2ban.example.org"}
```
## Agent settings
Protected addresses and the manual jail are configured **on each host** in
`/etc/f2b-webctl.conf` – see [agent.md](agent.md#configuration--etcf2b-webctlconf).