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

11 KiB
Raw Permalink Blame History

Agent – f2b-webctl

Auf jedem fail2ban-Host läuft der Agent f2b-webctl: ein kleines Python-Skript (nur Standardbibliothek), das als SSH-Forced-Command für den Schlüssel der Weboberfläche gestartet wird. Etwas anderes kann die Weboberfläche auf dem Host nicht ausführen.

Befehl (von der Weboberfläche) Wirkung
list alle Jails mit ihren gesperrten IPs (JSON)
ban <ip> dauerhaft im manuellen Jail (manual-block) sperren
unban <jail> <ip> in einem Jail entsperren
unban-all <ip> in allen Jails entsperren
version Agent-Version

Wird nie gesperrt, egal was die Weboberfläche schickt:

  • private, Loopback-, Link-Local-, CGNAT-, Multicast- und reservierte Bereiche (10/8, 172.16/12, 192.168/16, 100.64/10, 127/8, 169.254/16, fc00::/7, fe80::/10, …)
  • alle Adressen des Hosts selbst und die Adresse, von der die Weboberfläche zugreift
  • alles, was unter PROTECTED in /etc/f2b-webctl.conf steht (z. B. deine Heim-IP)

Jede Aktion landet im Syslog (Facility auth, Tag f2b-webctl), auch abgelehnte.

Voraussetzungen

fail2ban ≥ 0.11, laufend (fail2ban-client ping) – ältere Versionen ohne --with-time funktionieren, aber ohne Start-/Endzeiten
python3 ≥ 3.8
sshd vom Webui-Host erreichbar
sudo für den Standardbenutzer f2bweb (apt install sudo); mit --user root nicht nötig
bash, ssh-keygen für den Installer

Läuft auf Debian, Ubuntu, Proxmox VE und anderen Linux-Systemen mit oder ohne systemd – Bare Metal, VMs, LXC-Container (privilegiert oder unprivilegiert) und Docker-Hosts.

Installation

Gebraucht werden der öffentliche Schlüssel aus fail2ban-webui keygen und die Adresse, von der die Weboberfläche zugreift (öffentliche IP des Docker-Hosts oder seine LAN-Adresse).

# als root auf dem fail2ban-Host
git clone https://git.retronerd.at/schiwagoa/fail2ban-webui.git /tmp/fail2ban-webui
cd /tmp/fail2ban-webui/agent

echo 'ssh-ed25519 AAAA… fail2ban-webui' > /tmp/webui.pub

# anzeigen, was passieren würde
bash install.sh --key-file /tmp/webui.pub --from 198.51.100.10 --dry-run
# installieren
bash install.sh --key-file /tmp/webui.pub --from 198.51.100.10

Ohne git: die drei Dateien f2b-webctl, install.sh und uninstall.sh aus dem Ordner agent/ in ein Verzeichnis laden und install.sh von dort starten.

Der Installer zeigt eine Zusammenfassung und fragt, bevor er etwas ändert:

fail2ban-webui agent 1.0.0  –  fail2ban 1.1.0  –  web01

  script         /usr/local/sbin/f2b-webctl
  config         /etc/f2b-webctl.conf
  SSH user       f2bweb (will be created)
  sudo rule      /etc/sudoers.d/f2b-webctl
  key file       /var/lib/f2bweb/.ssh/authorized_keys
  key            256 SHA256:zfwh… (ED25519)
  allowed from   198.51.100.10
  manual jail    manual-block (will be created)
  backups        /var/backups/fail2ban-webui-agent

Was er tut:

  1. sichert jede Datei, die er ändert, nach --backup-dir
  2. installiert /usr/local/sbin/f2b-webctl (root:root 0750)
  3. schreibt /etc/f2b-webctl.conf (bleibt erhalten, wenn sie schon existiert)
  4. legt den Systembenutzer f2bweb an (Home /var/lib/f2bweb, ohne Passwort) und die sudo-Regel
    Defaults!/usr/local/sbin/f2b-webctl env_keep += "SSH_ORIGINAL_COMMAND SSH_CLIENT"
    f2bweb ALL=(root) NOPASSWD: /usr/local/sbin/f2b-webctl
    
  5. trägt den Schlüssel mit allen Einschränkungen ein:
    restrict,from="198.51.100.10",command="sudo -n /usr/local/sbin/f2b-webctl" ssh-ed25519 AAAA… fail2ban-webui
    
  6. legt das Jail manual-block an, falls es noch nicht existiert (siehe unten)
  7. führt einen Selbsttest über denselben sudo-Weg aus, den die Weboberfläche nutzt

Den Installer erneut auszuführen ist unbedenklich: Er aktualisiert das Skript, ersetzt den Schlüsseleintrag und lässt deine Konfiguration unverändert.

Optionen

Option Standard Bedeutung
--key-file DATEI / --key "SCHLÜSSEL" – öffentlicher Schlüssel der Weboberfläche (Pflicht)
--from ADRESSEN jede Schlüssel nur von diesen IPs/Netzen akzeptieren (durch Komma getrennt). Dringend empfohlen.
--user NAME f2bweb SSH-Benutzer; root funktioniert ohne sudo
--authorized-keys-file PFAD ~USER/.ssh/authorized_keys wohin der Schlüsseleintrag kommt – siehe verwaltete Schlüssel
--manual-jail NAME manual-block Jail für manuelle Sperren
--banaction AKTION aus jail.local Banaction für ein neu angelegtes manuelles Jail
--docker – Docker-Host: das neue manuelle Jail sperrt in INPUT und DOCKER-USER (iptables) – nicht mit --banaction kombinierbar
--protect NETZE – zusätzliche geschützte Adressen (nur wenn die Konfigurationsdatei geschrieben wird)
--no-jail – kein manuelles Jail anlegen
--force-config – vorhandene /etc/f2b-webctl.conf überschreiben
--backup-dir VERZEICHNIS /var/backups/fail2ban-webui-agent Sicherungen geänderter Dateien
--dry-run – nur anzeigen, was passieren würde
-y, --yes – nicht nachfragen

Der Installer warnt, wenn sshd die gewählte Schlüsseldatei gar nicht liest (AuthorizedKeysFile), wenn AllowUsers/AllowGroups gesetzt sind oder wenn --user root auf PermitRootLogin no trifft.

Das manuelle Jail

Sperren aus der Weboberfläche landen in einem Jail, standardmäßig manual-block, mit bantime = -1 (dauerhaft). Gibt es das Jail noch nicht, legt der Installer an:

/etc/fail2ban/filter.d/manual-block.conf

# fail2ban-webui: never matches – the jail is only filled via
# "fail2ban-client set manual-block banip <ip>"
[Definition]
failregex = ^FAIL2BAN-WEBUI-NEVER-MATCHES <HOST>$
ignoreregex =

/etc/fail2ban/jail.d/manual-block.local

# fail2ban-webui: permanent manual bans from the web UI
[manual-block]
enabled  = true
filter   = manual-block
backend  = polling
logpath  = /var/log/fail2ban-manual-block.log
maxretry = 1
bantime  = -1

Das Jail nutzt deine Standard-banaction aus jail.local. Sperren überstehen Neustarts über die fail2ban-Datenbank.

Ein vorhandenes Jail mit diesem Namen wird nie angefasst – gibt es schon ein Jail für manuelle Sperren, dessen Namen mit --manual-jail übergeben.

Docker-Hosts

Die Standardaktionen von fail2ban sperren in der Kette INPUT. Verkehr zu veröffentlichten Docker-Ports läuft aber nicht über INPUT, sondern über FORWARD → DOCKER-USER; solche Sperren würden deine Container also nicht schützen. Auf einem Docker-Host den Agenten deshalb mit --docker installieren – das manuelle Jail sperrt dann in beiden Ketten:

bash install.sh --key-file /tmp/webui.pub --from 198.51.100.10 --docker

Das erzeugt im Jail:

action   = iptables-allports[name=manual-block]
           iptables-allports[name=manual-block-docker, chain=DOCKER-USER]

Ein schon vorhandenes Jail ändert der Installer nicht; die zwei Zeilen dann von Hand in /etc/fail2ban/jail.d/manual-block.local eintragen und fail2ban-client reload ausführen.

Nach der ersten Sperre prüfen:

iptables -S DOCKER-USER | grep f2b

Läuft die Weboberfläche auf demselben Docker-Host, in hosts.yaml address: host.docker.internal verwenden und SSH aus dem Docker-Netz erlauben, falls eine Firewall (z. B. UFW) es blockiert:

ufw allow from 172.23.51.0/24 to any port 22 proto tcp comment 'fail2ban-webui'

und den Agenten mit --from 172.23.51.10 installieren.

LXC-Container

Der Agent läuft im Container, in dem fail2ban läuft – sonst ist nichts Besonderes nötig. In unprivilegierten Containern muss fail2ban selbst die Firewall des Containers ändern können (nftables/iptables im CT); mit einer manuellen Sperre testen:

fail2ban-client set manual-block banip 203.0.113.1 && nft list ruleset | grep 203.0.113.1
fail2ban-client set manual-block unbanip 203.0.113.1

Hosts mit verwalteten authorized_keys

Manche Werkzeuge (Ansible, Keywarden, cloud-init, …) überschreiben ~/.ssh/authorized_keys. Den Schlüssel dann in eine Datei legen, die sie nicht verwalten, und sicherstellen, dass sshd sie liest:

grep -i '^AuthorizedKeysFile' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf
# z. B. AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2

bash install.sh --key-file /tmp/webui.pub --from 198.51.100.10 \
  --user root --authorized-keys-file /root/.ssh/authorized_keys2

Konfiguration – /etc/f2b-webctl.conf

# fail2ban-webui agent (f2b-webctl) – settings
# Jail used for manual bans from the web UI
MANUAL_JAIL=manual-block
# Addresses/networks that must never be banned (comma separated), e.g. your home IP.
# Private, loopback, link-local and CGNAT ranges are always protected.
PROTECTED=203.0.113.25,2001:db8:1234::/48
# Also protect all addresses of this host and the address of the web UI (yes/no)
PROTECT_OWN_ADDRESSES=yes
PROTECT_CLIENT=yes

Änderungen wirken sofort – der Agent liest die Datei bei jedem Aufruf.

Test auf dem Host

# direkt als root
f2b-webctl list | python3 -m json.tool | head -30
f2b-webctl ban 10.0.0.1          # → abgelehnt, geschützt

# derselbe Weg wie die Weboberfläche (Benutzer f2bweb über sudo)
runuser -u f2bweb -- env SSH_ORIGINAL_COMMAND=version sudo -n /usr/local/sbin/f2b-webctl

# was der Agent getan hat
journalctl -t f2b-webctl --since today      # oder: grep f2b-webctl /var/log/auth.log

Aktualisieren

Den Installer der neuen Version mit denselben Optionen erneut ausführen. Konfiguration und Jail bleiben erhalten; Skript und Schlüsseleintrag werden ersetzt.

Deinstallieren

bash uninstall.sh --dry-run
bash uninstall.sh
Option Bedeutung
--user NAME Agent-Benutzer (Standard f2bweb)
--authorized-keys-file PFAD Datei mit dem Schlüsseleintrag
--remove-user auch den Benutzer samt Home löschen
--remove-jail auch das manuelle Jail löschen – hebt alle manuellen Sperren auf (sie werden vorher aufgelistet)
--backup-dir VERZEICHNIS, --dry-run, --yes wie beim Installer

Manuelle Installation

Wer es lieber von Hand macht – das sind alle Schritte des Installers:

install -o root -g root -m 0750 f2b-webctl /usr/local/sbin/f2b-webctl
nano /etc/f2b-webctl.conf                          # Inhalt siehe oben

useradd --system --create-home --home-dir /var/lib/f2bweb --shell /bin/sh f2bweb
usermod -p '*' f2bweb
visudo -f /etc/sudoers.d/f2b-webctl                # Inhalt siehe "Was er tut", Schritt 4

install -d -o f2bweb -g f2bweb -m 700 /var/lib/f2bweb/.ssh
nano /var/lib/f2bweb/.ssh/authorized_keys          # Zeile siehe Schritt 5
chown f2bweb: /var/lib/f2bweb/.ssh/authorized_keys
chmod 600 /var/lib/f2bweb/.ssh/authorized_keys

# manuelles Jail: die zwei Dateien aus "Das manuelle Jail", dann
touch /var/log/fail2ban-manual-block.log
fail2ban-client reload