# fail2ban-webui Eine schlanke, selbst gehostete Weboberfläche, um **fail2ban-Sperren auf mehreren Hosts anzuzeigen, zu setzen und aufzuheben** – Bare Metal, VMs, LXC-Container oder Docker-Hosts. - Eine Seite für alle Hosts: aktuelle Sperren pro Jail, Herkunft (GeoIP) mit Weltkarte, Suche und Filter - IP dauerhaft auf beliebigen Hosts sperren, pro Jail oder überall entsperren - Protokoll jeder Aktion (wer, wann, von wo) - Optional: Log-Verlauf pro IP aus **Loki**, Links nach **Grafana** - Anmeldung mit lokalem Benutzer, **OpenID Connect** (z. B. Authentik) oder über den Reverse Proxy - Oberfläche auf Englisch und Deutsch, weitere Sprachen über eine JSON-Datei - Läuft als gehärteter Container (schreibgeschützt, ohne Capabilities, nicht als root), `amd64` und `arm64` ``` Browser ──HTTPS──▶ Reverse Proxy ──▶ fail2ban-webui (Docker) │ SSH, ein eingeschränkter Schlüssel ┌─────────────────────┼─────────────────────┐ ▼ ▼ ▼ Host A (Bare Metal) LXC-Container Docker-Host f2b-webctl f2b-webctl f2b-webctl fail2ban fail2ban fail2ban ``` Die Weboberfläche bekommt nie eine Shell auf deinen Hosts. Auf jedem Host läuft ein kleiner Agent, [`f2b-webctl`](agent/f2b-webctl), als SSH-*Forced-Command*. Er kennt nur `list`, `ban `, `unban `, `unban-all ` und `version`, sperrt niemals private Netze, die eigenen Adressen des Hosts oder Einträge seiner Schutzliste und protokolliert jede Aktion im Syslog. Zugriff auf den fail2ban-Socket wäre gleichbedeutend mit root – die Sicherheitsgrenze ist der Agent, nicht die Weboberfläche. ## Voraussetzungen Getestet auf Ubuntu 24.04/26.04 und Debian 12/13 – Bare Metal, VM oder LXC. Alle Befehle als root. ### Grundpakete (alle Hosts) ```bash apt update apt install -y curl git apt install -y mc # optional: Midnight Commander als Dateimanager ``` ### Docker-Host (Weboberfläche) Gebraucht wird eine vollständige Docker-Umgebung – Docker Engine **und** das Compose-Plugin (Befehl `docker compose` mit Leerzeichen), `amd64` oder `arm64`. Auf Ubuntu 24.04/26.04 z. B. mit dem [Docker-Installer](https://git.retronerd.at/schiwagoa/public-docker-installer-26.04-v1): ```bash git clone https://git.retronerd.at/schiwagoa/public-docker-installer-26.04-v1.git cd public-docker-installer-26.04-v1 chmod +x *.sh ./docker-installer-2604-v1.sh ``` Diese Anleitung verwendet `docker compose` (Plugin). Der Installer richtet zusätzlich das eigenständige `docker-compose` ein; das Plugin kommt normalerweise mit `docker-ce` mit. Prüfen – beide Befehle müssen eine Version ausgeben: ```bash docker version --format '{{.Server.Version}}' docker compose version ``` Meldet `docker compose version` den Fehler `'compose' is not a docker command`, das Plugin nachinstallieren: `apt install -y docker-compose-plugin`. In einem **LXC-Container** braucht Docker auf dem Proxmox-Host die Features `nesting=1,keyctl=1` (unprivilegierter Container: `pct set --features nesting=1,keyctl=1`, danach den Container neu starten). ### fail2ban-Hosts (Agent) - fail2ban ≥ 0.11 (Start-/Endzeiten der Sperren brauchen `--with-time`) - `sudo` für den Standardbenutzer `f2bweb`; mit einem root-Schlüssel nicht nötig - `bash`, `ssh-keygen` (Teil von OpenSSH) für den Installer ## Installation auf einem Host Weboberfläche und Agent auf demselben Docker-Host – so getestet auf Ubuntu 26.04 (LXC). Weitere fail2ban-Hosts kommen später nur mit dem Agenten dazu ([docs/agent.md](docs/agent.md)). Im Beispiel hat der Host die LAN-Adresse `192.168.1.10` – überall durch deine ersetzen. ### fail2ban vorbereiten ```bash apt install -y fail2ban python3 sudo openssh-server ``` ```bash systemctl enable --now fail2ban ``` ```bash fail2ban-client ping # Server replied: pong ``` ### Quellen holen ```bash git clone https://git.retronerd.at/schiwagoa/fail2ban-webui.git /opt/fail2ban-webui-src ``` ### Weboberfläche einrichten ```bash mkdir -p /opt/fail2ban-webui/{config,data} && cd /opt/fail2ban-webui ``` ```bash curl -fsSLo docker-compose.yaml https://git.retronerd.at/schiwagoa/fail2ban-webui/raw/branch/main/examples/docker-compose.yaml ``` ```bash curl -fsSLo .env https://git.retronerd.at/schiwagoa/fail2ban-webui/raw/branch/main/examples/.env.example ``` Der Container läuft als UID 10050 und muss in `data/` schreiben: ```bash chown -R 10050:10050 data && chmod 700 data ``` Für den Zugriff direkt im LAN (ohne Reverse Proxy) den Port an die LAN-Adresse binden – hinter einem Nginx Proxy Manager diesen Schritt [weglassen](#hinter-einem-vorhandenen-nginx-proxy-manager-docker): ```bash sed -i 's/"127.0.0.1:8080:8080"/"192.168.1.10:8080:8080"/' docker-compose.yaml ``` Adresse, Sprache und Proxy-Einstellung setzen. Ohne TLS muss `PUBLIC_URL` mit `http://` beginnen, sonst schickt der Browser das Sitzungs-Cookie nicht mit; ohne Proxy gehört `TRUSTED_PROXY_HOPS` auf `0`: ```bash sed -i -e 's|^PUBLIC_URL=.*|PUBLIC_URL=http://192.168.1.10:8080|' -e 's|^DEFAULT_LANG=.*|DEFAULT_LANG=de|' -e 's|^TRUSTED_PROXY_HOPS=.*|TRUSTED_PROXY_HOPS=0|' .env ``` Passwort-Hash erzeugen (mindestens 12 Zeichen, zweimal eingeben): ```bash docker compose run --rm -it fail2ban-webui hash-password ``` Die ausgegebene Zeile `AUTH_PASSWORD_HASH='scrypt:…'` kopieren und in der `.env` die Zeile `AUTH_PASSWORD_HASH='scrypt:...'` damit ersetzen – die einfachen Anführungszeichen bleiben: ```bash nano .env ``` SSH-Schlüssel der Weboberfläche erzeugen: ```bash docker compose run --rm fail2ban-webui keygen ``` ### Agent installieren Probelauf – zeigt nur, was passieren würde. `172.23.51.10` ist die feste Adresse der Weboberfläche in ihrem Docker-Netz: ```bash bash /opt/fail2ban-webui-src/agent/install.sh --key-file /opt/fail2ban-webui/data/ssh/id_ed25519.pub --from 172.23.51.10 --dry-run ``` Installieren und mit `y` bestätigen – am Ende meldet der Selbsttest `2 jails, 0 bans: manual-block, sshd`. Laufen auf dem Host weitere Docker-Dienste mit veröffentlichten Ports (z. B. ein Nginx Proxy Manager), zusätzlich `--docker` anhängen, damit manuelle Sperren auch dort greifen: ```bash bash /opt/fail2ban-webui-src/agent/install.sh --key-file /opt/fail2ban-webui/data/ssh/id_ed25519.pub --from 172.23.51.10 ``` ### Host eintragen und testen ```bash cat > config/hosts.yaml <<'EOF' hosts: - name: srv200 address: host.docker.internal EOF ``` Host-Schlüssel holen – die Fingerprints werden angezeigt, mit `y` bestätigen: ```bash docker compose run --rm -it fail2ban-webui keyscan ``` Verbindung testen – erwartet: `OK srv200 agent 1.0.0, 2 jails, 0 bans`: ```bash docker compose run --rm fail2ban-webui check ``` ### Starten ```bash docker compose up -d ``` ```bash docker compose ps # Up … (healthy) nach etwa 30 Sekunden ``` ```bash docker compose logs fail2ban-webui # hosts: srv200 – auth: local – geoip: on, danach "GeoIP database updated" ``` Im Browser `http://192.168.1.10:8080` öffnen und mit `admin` und dem Passwort von oben anmelden. > `docker compose run` funktioniert nur, solange der Dienst **nicht** läuft – die feste > IP-Adresse wäre sonst doppelt vergeben (`Address already in use`). Im laufenden Betrieb > die Hilfsbefehle mit `exec` aufrufen, z. B. `docker compose exec fail2ban-webui python -m webui check`. ## Hinter einem vorhandenen Nginx Proxy Manager (Docker) Ausgangslage: Nginx Proxy Manager (NPM) läuft auf demselben Host als Docker-Container, fail2ban ist auf dem Host installiert. Die Weboberfläche bekommt dann **keinen** veröffentlichten Port, sondern hängt zusätzlich im Docker-Netz von NPM; erreichbar ist sie nur über NPM mit TLS. Voraussetzung: Docker Engine ≥ 28 und Compose ≥ 2.33 (für `gw_priority`, siehe Schritt 3). ### 1. Manuelle Sperren auch für Docker-Ports Verkehr zu veröffentlichten Docker-Ports – also auch zu NPM – läuft nicht über die Kette `INPUT`, sondern über `DOCKER-USER`. Den Agenten deshalb mit `--docker` installieren: ```bash bash /opt/fail2ban-webui-src/agent/install.sh --key-file /opt/fail2ban-webui/data/ssh/id_ed25519.pub --from 172.23.51.10 --docker ``` War der Agent schon ohne `--docker` installiert, lässt der Installer das vorhandene Jail unverändert. Dann die Datei sichern, die zwei `action`-Zeilen ergänzen und fail2ban neu laden: ```bash mkdir -p /backups/config_backups && cp -a /etc/fail2ban/jail.d/manual-block.local /backups/config_backups/manual-block.local_$(date +%F_%H-%M) ``` ```bash nano /etc/fail2ban/jail.d/manual-block.local ``` ```ini action = iptables-allports[name=manual-block] iptables-allports[name=manual-block-docker, chain=DOCKER-USER] ``` ```bash fail2ban-client reload && fail2ban-client status manual-block ``` ### 2. Docker-Netz von NPM ermitteln ```bash docker ps --format '{{.Names}} {{.Image}}' | grep -iE 'npm|proxy-manager' ``` ```bash docker inspect --format '{{range $n, $c := .NetworkSettings.Networks}}{{$n}}{{"\n"}}{{end}}' ``` ### 3. Weboberfläche ins NPM-Netz hängen Den veröffentlichten Port entfernen – erreichbar ist die Oberfläche danach nur noch über NPM: ```bash cd /opt/fail2ban-webui && sed -i '/^ ports:$/,/8080:8080"$/d' docker-compose.yaml ``` Das NPM-Netz kommt in eine eigene Datei `docker-compose.override.yaml`, die Docker Compose automatisch dazulädt. Den Netznamen aus Schritt 2 in `NPM_NET` setzen: ```bash NPM_NET=npm_default ``` ```bash cat > docker-compose.override.yaml < 🏰 Website · 🐘 Mastodon · 🔒 Datenschutz · 💬 Support

© Thomas Werner Schwaighofer · retronerd.AT · MIT Lizenz