- 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>
127 lines
4.1 KiB
Markdown
127 lines
4.1 KiB
Markdown
# Reverse Proxy
|
||
|
||
Der Container liefert reines HTTP auf Port 8080 (im Beispiel veröffentlicht als
|
||
`127.0.0.1:8080`). Davor gehört ein Reverse Proxy mit TLS; in der `.env` dazu setzen:
|
||
|
||
```ini
|
||
PUBLIC_URL=https://fail2ban.example.org
|
||
TRUSTED_PROXY_HOPS=1
|
||
```
|
||
|
||
Der Proxy muss `Host` unverändert weitergeben und `X-Forwarded-For` sowie `X-Forwarded-Proto`
|
||
setzen – alle Beispiele unten tun das. Den Zugriff am Proxy zusätzlich auf bekannte
|
||
IP-Adressen zu beschränken kostet wenig und ist dringend empfohlen.
|
||
|
||
## Nginx Proxy Manager
|
||
|
||
Läuft NPM als Docker-Container auf demselben Host: die getestete Schritt-für-Schritt-Anleitung
|
||
steht im [README](../README.md#hinter-einem-vorhandenen-nginx-proxy-manager-docker) (gemeinsames
|
||
Docker-Netz, kein veröffentlichter Port, `gw_priority`, Sperren in `DOCKER-USER`).
|
||
Für NPM auf einem anderen Host:
|
||
|
||
**Hosts → Proxy Hosts → Add Proxy Host**
|
||
|
||
| Feld | Wert |
|
||
|---|---|
|
||
| Domain Names | `fail2ban.example.org` |
|
||
| Scheme / Forward Hostname / Port | `http` · IP des Docker-Hosts (oder `127.0.0.1`, wenn NPM im Host-Netzwerk läuft) · `8080` |
|
||
| Block Common Exploits | an |
|
||
| SSL | Zertifikat anfordern, *Force SSL*, *HTTP/2*, *HSTS* |
|
||
| Access List | optional: eine Access List mit deinen IP-Adressen (*Satisfy any* aus) |
|
||
|
||
Läuft NPM auf demselben Host in einem anderen Docker-Netz, den Port der Oberfläche an die
|
||
LAN-Adresse des Hosts binden (z. B. `"192.168.1.10:8080:8080"`) oder die Oberfläche an das
|
||
Netz von NPM hängen und `fail2ban-webui:8080` als Ziel verwenden.
|
||
|
||
Antwort-Header gehören nach **Advanced → Custom Nginx Configuration**; das NPM-Image enthält
|
||
das Modul *headers-more*, das sie auch auf weitergeleitete Antworten anwendet:
|
||
|
||
```nginx
|
||
more_set_headers "Strict-Transport-Security: max-age=31536000; includeSubDomains";
|
||
```
|
||
|
||
(CSP, `X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy` und `Cache-Control`
|
||
setzt die App selbst.)
|
||
|
||
## Caddy
|
||
|
||
```caddy
|
||
fail2ban.example.org {
|
||
@allowed remote_ip 203.0.113.0/24 2001:db8::/32
|
||
handle @allowed {
|
||
reverse_proxy 127.0.0.1:8080
|
||
}
|
||
respond 403
|
||
}
|
||
```
|
||
|
||
Caddy setzt `X-Forwarded-For`/`-Proto` automatisch.
|
||
|
||
## Traefik (Docker-Labels)
|
||
|
||
Den Container an das Netz von Traefik hängen und Labels setzen, statt den Port zu veröffentlichen:
|
||
|
||
```yaml
|
||
services:
|
||
fail2ban-webui:
|
||
# … as in the example compose file, without "ports:"
|
||
labels:
|
||
- traefik.enable=true
|
||
- traefik.http.routers.f2bwebui.rule=Host(`fail2ban.example.org`)
|
||
- traefik.http.routers.f2bwebui.entrypoints=websecure
|
||
- traefik.http.routers.f2bwebui.tls.certresolver=letsencrypt
|
||
- traefik.http.routers.f2bwebui.middlewares=f2bwebui-ipallow
|
||
- traefik.http.middlewares.f2bwebui-ipallow.ipallowlist.sourcerange=203.0.113.0/24
|
||
- traefik.http.services.f2bwebui.loadbalancer.server.port=8080
|
||
networks:
|
||
- fail2ban-webui.dockernetwork.local
|
||
- traefik
|
||
```
|
||
|
||
### Traefik mit Authentik Forward Auth (Proxy-Modus)
|
||
|
||
```yaml
|
||
- traefik.http.routers.f2bwebui.middlewares=authentik@docker
|
||
```
|
||
|
||
```ini
|
||
AUTH_MODE=proxy
|
||
AUTH_PROXY_HEADER=X-authentik-username
|
||
AUTH_PROXY_ALLOWED_IPS=<address of Traefik in the shared network>/32
|
||
AUTH_PROXY_LOGOUT_URL=https://fail2ban.example.org/outpost.goauthentik.io/sign_out
|
||
```
|
||
|
||
## nginx
|
||
|
||
```nginx
|
||
server {
|
||
listen 443 ssl;
|
||
http2 on;
|
||
server_name fail2ban.example.org;
|
||
|
||
ssl_certificate /etc/letsencrypt/live/fail2ban.example.org/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/fail2ban.example.org/privkey.pem;
|
||
|
||
allow 203.0.113.0/24;
|
||
deny all;
|
||
|
||
location / {
|
||
proxy_pass http://127.0.0.1:8080;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_read_timeout 90s; # several slow agents can take a while
|
||
}
|
||
}
|
||
```
|
||
|
||
## Prüfen
|
||
|
||
```bash
|
||
curl -sI https://fail2ban.example.org/login | grep -iE '^(HTTP|content-security|set-cookie)'
|
||
```
|
||
|
||
Erwartet werden `HTTP/2 200`, der Header `Content-Security-Policy` und ein Sitzungs-Cookie
|
||
mit `Secure; HttpOnly; SameSite=Lax`. Fehlt `Secure` am Cookie, beginnt `PUBLIC_URL` nicht
|
||
mit `https://`.
|