Files
schiwagoaandClaude Opus 5.5 b36499bbf5 Docs: tested single-host install, NPM integration, installer --docker
- README: step-by-step installation of web UI and agent on one host,
  exactly as tested (agent after keygen, all "run" helpers before
  "up -d", http PUBLIC_URL and TRUSTED_PROXY_HOPS=0 without a proxy)
- README: attach to an existing Nginx Proxy Manager in Docker – shared
  network via docker-compose.override.yaml, no published port,
  gw_priority so SSH to the agent keeps the source address of the own
  network (otherwise from= rejects it), TLS settings, test
- install.sh --docker: the new manual jail bans in INPUT and DOCKER-USER
- Running container: helpers via "docker compose exec … python -m webui"
  (run fails with "Address already in use"); troubleshooting entries

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 19:50:33 +01:00

156 lines
7.3 KiB
Markdown
Raw Permalink 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.
# Betrieb
Alle Befehle im Verzeichnis mit der `docker-compose.yaml` ausführen (z. B. `/opt/fail2ban-webui`).
## Status und Logs
```bash
docker compose ps # Up … (healthy)
docker compose logs --tail 100 fail2ban-webui
docker compose logs -f fail2ban-webui | grep -E 'AUDIT|LOGIN|ERROR|WARNING'
docker compose exec fail2ban-webui python -m webui check # jeder Agent erreichbar?
```
Wichtige Logzeilen:
| Zeile | Bedeutung |
|---|---|
| `fail2ban-webui 1.0.0 – hosts: … – auth: … – loki: … – geoip: …` | Zusammenfassung beim Start |
| `AUDIT {…}` | Sperren/Entsperren mit Benutzer, Client-IP, Hosts und Ergebnis |
| `LOGIN_OK` / `LOGIN_FAILED` / `LOGIN_LOCKED` / `LOGOUT` | Anmeldeereignisse |
| `OIDC_FAILED` / `OIDC_DENIED` | SSO-Fehler / Konto nicht zugelassen |
Das Protokoll liegt zusätzlich in `data/audit.log` (ein JSON-Objekt pro Zeile):
```bash
tail -n 20 data/audit.log | python3 -m json.tool --json-lines
```
Auf den Hosts steht jede Agent-Aktion im Syslog:
```bash
journalctl -t f2b-webctl --since today
```
## Update
```bash
cp -a .env docker-compose.yaml config /backups/fail2ban-webui_$(date +%F)/ # oder dein Backup-Ort
docker compose pull
docker compose up -d
docker compose ps
docker compose exec fail2ban-webui python -m webui check
```
Vorher das [Changelog](../CHANGELOG.md) lesen – nennt es eine neue Agent-Version, auch die
Agenten aktualisieren (`install.sh` mit denselben Optionen erneut ausführen, siehe
[agent.md](agent.md#aktualisieren)). Der Tag `1` bewegt sich nur innerhalb von 1.x;
inkompatible Änderungen bekommen eine neue Hauptversion.
Auch ohne neue Funktionen regelmäßig neu ziehen bzw. bauen: Das Image wird mit aktuellen
Debian-Sicherheitsupdates neu gebaut.
## Backup
| Was | Warum |
|---|---|
| `.env` | Einstellungen, Passwort-Hash, OIDC-Secret |
| `config/hosts.yaml` | Hostliste |
| `data/ssh/` | privater Schlüssel und festgelegte Host-Schlüssel – ohne sie braucht jeder Agent den neuen Schlüssel |
| `data/audit.log` | Protokoll |
| `data/secret_key` | hält nur Sitzungen gültig; geht er verloren, werden alle abgemeldet |
`data/geoip/` wird automatisch neu heruntergeladen.
```bash
tar -cpzf /backups/fail2ban-webui_$(date +%F_%H-%M).tar.gz .env docker-compose.yaml config data
sha256sum /backups/fail2ban-webui_*.tar.gz | tail -n1
```
Das Archiv enthält den privaten SSH-Schlüssel – entsprechend sicher aufbewahren.
## Umzug auf einen anderen Host
1. Auf dem alten Host `docker compose stop`, Archiv wie oben erstellen.
2. Kopieren, mit `tar -xpzf` entpacken (behält Besitzer 10050 und Rechte).
3. Auf **jedem Agenten** die neue Adresse in `from=` aufnehmen – am einfachsten
`install.sh … --from <neue Adresse>` erneut ausführen.
4. `docker compose up -d`, danach `check`.
## SSH-Schlüssel tauschen
```bash
docker compose run --rm fail2ban-webui keygen --force
# auf jedem Host:
bash install.sh --key-file new.pub --from … (dieselben Optionen wie zuvor)
```
Der Installer ersetzt nur Einträge mit demselben Schlüssel; den alten vorher mit
`uninstall.sh` entfernen oder seine Zeile aus `authorized_keys` löschen (sie enthält
`command="…f2b-webctl"`).
## Login mit fail2ban absichern
Die Oberfläche sperrt einen Client nach 5 Fehlversuchen selbst. Um hartnäckige Angreifer an
der Firewall zu sperren, liest fail2ban auf dem **Proxy-Host** das Container-Log.
`/etc/fail2ban/filter.d/fail2ban-webui.conf`
```ini
[Definition]
# Docker json-file log: {"log":"… WARNING webui: LOGIN_FAILED user=x ip=203.0.113.7\n",…}
# user names never contain spaces (they are sanitised), so only the real " ip=" matches
failregex = LOGIN_FAILED user=\S* ip=<HOST>
LOGIN_LOCKED ip=<HOST>
ignoreregex =
```
`/etc/fail2ban/jail.d/fail2ban-webui.local`
```ini
[fail2ban-webui]
enabled = true
filter = fail2ban-webui
backend = polling
logpath = /var/lib/docker/containers/*/*-json.log
maxretry = 5
findtime = 1h
bantime = 1d
# the proxy runs in Docker? Then ban in the DOCKER-USER chain:
# banaction = iptables-allports[chain=DOCKER-USER]
```
```bash
fail2ban-client reload
fail2ban-regex /var/lib/docker/containers/*/*-json.log /etc/fail2ban/filter.d/fail2ban-webui.conf
```
Das funktioniert nur, wenn der Container die echte Client-Adresse sieht (`TRUSTED_PROXY_HOPS`
richtig gesetzt). Benutzernamen werden mit ersetzten Leer- und Steuerzeichen protokolliert;
ein präparierter Benutzername kann also keine zweite Logzeile einschleusen.
## Fehlersuche
| Symptom | Ursache / Lösung |
|---|---|
| `curl: command not found` / `git: command not found` | frisches Minimal-System (z. B. LXC-Template) → `apt install -y curl git` |
| `failed to set up container networking: Address already in use` | `docker compose run …` bei laufendem Dienst – die feste IP ist belegt → `docker compose exec fail2ban-webui python -m webui <befehl>` |
| `Permission denied (publickey)` nur hinter NPM | Container hängt in zwei Netzen und verbindet mit der Adresse aus dem NPM-Netz → `gw_priority: 1` am eigenen Netz, siehe [README](../README.md#3-weboberfläche-ins-npm-netz-hängen) |
| `docker: 'compose' is not a docker command` | nur das eigenständige `docker-compose` vorhanden → `apt install -y docker-compose-plugin` |
| Container beendet sich: `… is not writable for UID 10050` | `chown -R 10050:10050 data` |
| Container beendet sich: `AUTH_MODE=local needs AUTH_PASSWORD_HASH` | `hash-password` ausführen, Zeile mit einfachen Anführungszeichen einfügen |
| Container beendet sich: `No hosts configured` | `config/hosts.yaml` fehlt oder ist leer; unter Windows/Docker Desktop: das Laufwerk lässt sich nicht einbinden |
| Anmeldung scheitert immer, nachdem der Hash eingefügt wurde | einfache Anführungszeichen in der `.env` fehlen – Compose hat die `$`-Teile verschluckt |
| Alle werden gemeinsam gesperrt / Protokoll zeigt die Proxy-IP | `TRUSTED_PROXY_HOPS` nicht gesetzt |
| `Host key verification failed` | Host nicht in `known_hosts` oder sein Schlüssel hat sich geändert → `keyscan`, Fingerprints vergleichen |
| `Permission denied (publickey)` | Schlüssel für diesen Benutzer nicht installiert, falsches `user:` in `hosts.yaml`, falsches `from=` (die Adresse, die der Host sieht!) oder sshd liest diese `authorized_keys`-Datei nicht |
| `sudo: a password is required` | sudo-Regel fehlt → `install.sh` erneut ausführen |
| `The agent does not run as root` | Forced-Command ohne `sudo -n` für einen Nicht-root-Benutzer → `install.sh` erneut ausführen |
| `Timeout talking to …` | Firewall/Port, oder der Host ist langsam – `SSH_TIMEOUT` erhöhen |
| `The jail manual-block does not exist on this host` | mit `--no-jail` oder einem anderen `--manual-jail` installiert; `MANUAL_JAIL` in `/etc/f2b-webctl.conf` prüfen |
| Sperren haben keine Start-/Endzeit | fail2ban älter als 0.11 (kein `--with-time`) |
| Gesperrte IP erreicht trotzdem einen Docker-Dienst | Banaction sperrt nur `INPUT` – siehe [Docker-Hosts](agent.md#docker-hosts) |
| OIDC: `redirect_uri` passt nicht | Provider muss genau `<PUBLIC_URL>/auth/callback` erlauben |
| OIDC: `mismatching_state` | Sitzungs-Cookie zwischen Weiterleitung und Callback verloren: Host in `PUBLIC_URL` weicht vom Browser ab, oder `https` ohne `Secure`/Proxy-Header |
| OIDC: „Konto … darf diese Anwendung nicht verwenden" | Benutzer nicht in `OIDC_ALLOWED_GROUPS`; prüfen, ob der Provider den Claim `groups` mitschickt |