# 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 run --rm fail2ban-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 run --rm fail2ban-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 ` 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= LOGIN_LOCKED ip= 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 | |---|---| | 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 `/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 |