Seit Artikel 07 ist Caddy der eine kontrollierte Eingang von außen. UFW erlaubt 80 und 443, alles dahinter läuft intern. Seit Artikel 09 sitzt vor jeder persönlichen App zusätzlich Authelia mit 2FA. Das ist solide – aber es ist statisch. Wer dich angreift, kommt zwar nicht durch, aber er kann es beliebig oft versuchen. Sein nächster Versuch sieht für dein Setup genauso aus wie der erste.
CrowdSec ergänzt genau diese Ebene: Es liest die Logs deiner öffentlichen Dienste, erkennt aggressive Muster (Brute Force, Scans, CVE-Versuche, bekannte Bots) und sagt Caddy, dass die jeweilige IP für eine Weile draußen bleibt. Und – das ist der eigentliche Trick – es nutzt zusätzlich eine community-gepflegte Liste bereits anderswo aufgefallener IPs. Wenn dich also eine IP angreift, die letzte Woche schon hundert andere CrowdSec-Nutzer angegriffen hat, bekommt sie von dir gar keinen Login-Schirm mehr zu sehen – sondern direkt eine Fehlerseite, ohne dass Authelia oder die App überhaupt befragt wird.
Das Plugin in Caddy ist seit Artikel 07 schon eingebaut, nur inaktiv. In diesem Artikel aktivierst du es.
Am Ende hast du
- CrowdSec liest die Logs deiner Web-Dienste mit und erkennt typische Angriffsmuster: massenhaft Passwort-Versuche, automatisches Abklappern bekannter Sicherheitslücken, Bot-Scans
- Erkannte Angreifer werden für eine Weile gesperrt – sie sehen statt deiner App nur eine Fehlerseite
- Die globale CrowdSec-Community-Blocklist ist aktiv: IPs, die gerade anderswo attackieren, werden bei dir präventiv geblockt, noch bevor sie es bei dir versuchen
- Deine eigene Heim-IP ist auf einer Whitelist und kommt nicht aus Versehen in eigene Sperren
- Du kannst per Kommandozeile jederzeit sehen, wer gerade gesperrt ist und warum
- Optional: Eine schlanke Web-Oberfläche zeigt Alerts und Bans direkt im Browser
- Optional: Eine zusätzliche Filterschicht prüft den Inhalt jedes einzelnen Requests und blockt typische Angriffe gegen Webanwendungen – noch bevor sie deine App erreichen
Voraussetzungen
- Artikel 02–07 abgeschlossen; Artikel 09, wenn du Authelia-Logs mit auswerten willst
- Caddy läuft mit dem Image
ghcr.io/serfriz/caddy-crowdsec:2(Artikel 07) und schreibt Access-Logs nach/srv/docker/stacks/caddy/logs/ - Komodo läuft, Server
homelabist eingebunden - Eine zweite externe IP zum Testen (z. B. dein Smartphone im Mobilfunknetz) – damit du dich nicht aus Versehen selbst aussperrst
1. Wie CrowdSec funktioniert
Bevor wir konfigurieren, ein Bild der Funktionsweise und die wichtigsten Begriffe – die tauchen im weiteren Artikel immer wieder auf:
- Bouncer ist der Türsteher – der Teil, der eine IP tatsächlich blockiert. In unserem Setup ist das Bouncer-Plugin schon im Caddy-Container drin.
- Decision ist eine konkrete Entscheidung: „IP 1.2.3.4 für 4 Stunden sperren". CrowdSec sammelt diese Decisions in einer kleinen Datenbank, der Bouncer holt sie sich von dort ab.
- Parser liest eine Logzeile und macht daraus strukturierte Daten (IP, URL, Status-Code).
- Scenario ist eine Regel: „wenn Bedingung X sich Y-mal in Z Sekunden wiederholt – dann eine Decision erzeugen". Parser und Scenarios kommen fertig aus dem CrowdSec-Hub, du installierst sie als Collection (Bundle für einen bestimmten Dienst, z. B. Caddy oder Authelia).
Was CrowdSec bringt:
- Verhaltenserkennung. Erkennt nicht nur einzelne böse Requests, sondern Muster über Zeit. Ein Login-Versuch ist harmlos, dreißig in zwei Minuten sind ein Brute-Force-Angriff.
- Community-Blocklist. Greift auf die zentrale CrowdSec-Datenbank zu. IPs, die anderswo auffällig waren, blockst du, bevor sie überhaupt einen Versuch unternehmen.
- App-übergreifend. Eine IP, die in Authelia 5× das Passwort falsch eintippt, sieht danach auch keine Vaultwarden-Seite, kein Immich, kein Ghost mehr – weil der Block beim Türsteher Caddy greift, nicht erst in der App.
- Updates ohne Nachpflege. Parser, Scenarios und CVE-Patterns kommen aus dem CrowdSec-Hub und werden automatisch aktualisiert.
Was CrowdSec nicht ersetzt:
- Kein Ersatz für Authelia. Authelia kontrolliert wer reinkommt (Account + 2FA). CrowdSec kontrolliert welche IPs überhaupt fragen dürfen. Beide Schichten zusammen sind sinnvoll, einzeln nur halb so wirksam.
- Kein Ersatz für die Firewall. UFW erlaubt 80/443 öffentlich, alles andere ist zu. CrowdSec filtert nur, was bei Caddy ankommt – andere Ports schließt weiterhin UFW.
- Kein Ersatz für ein Backup. Wenn ein Angreifer doch durchkommt, ändert CrowdSec daran nichts. Es macht es nur schwieriger, überhaupt anzukommen.
2. Log-Pfade freigeben
CrowdSec braucht Lesezugriff auf die Logs von Caddy und Authelia. Die Verzeichnisse liegen auf dem Host; CrowdSec läuft im Container als User nobody (UID 65534).
Per SSH prüfen, dass Logs existieren:
ls /srv/docker/stacks/caddy/logs/
ls /srv/docker/stacks/authelia/log/
Erwartung: .log-Dateien in beiden Verzeichnissen. Falls leer: kurz https://auth.deine-domain.de im Browser aufrufen – das reicht für einen ersten Eintrag.
Dann Leserechte setzen:
chmod o+rx /srv/docker/stacks/caddy/logs/
chmod o+rx /srv/docker/stacks/authelia/log/
Was
o+rxbedeutet:osteht für „others" – alles, was weder Owner noch Group ist.r= lesen,xauf einem Verzeichnis = hineingehen dürfen. Dateien darin behalten ihre eigenen Rechte. Keinchmod 777nötig.
3. Den Bouncer-Schlüssel vorab erzeugen
CrowdSec und der Caddy-Bouncer brauchen einen gemeinsamen Schlüssel, mit dem sich der Bouncer ausweist. Den erzeugen wir einmal vorab und tragen ihn in beide .env-Dateien ein – CrowdSec registriert ihn beim ersten Start automatisch, Caddy benutzt ihn fürs Plugin.
Auf dem Server:
openssl rand -hex 32
Den 64-Zeichen-Hex-Wert in den Passwort-Manager kopieren. Du brauchst ihn gleich zweimal: in der .env des CrowdSec-Stacks (als CROWDSEC_BOUNCER_KEY) und in der .env des Caddy-Stacks (als CROWDSEC_API_KEY). Beide Werte müssen exakt gleich sein.
Warum nicht erst CrowdSec starten und dann
cscli bouncers addbenutzen?Funktioniert auch – und ist der Weg, den die meisten Tutorials zeigen. Dafür müsstest du aber CrowdSec hochfahren, dich ins Terminal des Containers verbinden, den dort erzeugten Schlüssel in die Caddy-
.envkopieren und Caddy dann neu deployen. MitBOUNCER_KEY_<name>als Umgebungsvariable nimmt CrowdSec den Schlüssel beim ersten Start aus der.envund registriert ihn von selbst. Du kannst beide Stacks in beliebiger Reihenfolge deployen, und der Schlüssel existiert nur an zwei Stellen, die du eh kennst.
4. Stack in Komodo anlegen
In Komodo (http://homelab:9120):
- Links Stacks → oben rechts + New Stack
- Name:
crowdsec - Server:
homelab - Stack Type:
UI Defined - Create
5. compose.yaml
name: crowdsec
services:
crowdsec:
image: crowdsecurity/crowdsec:latest
container_name: crowdsec
restart: unless-stopped
env_file: .env
environment:
COLLECTIONS: "crowdsecurity/caddy crowdsecurity/http-cve LePresidente/authelia crowdsecurity/whitelist-good-actors"
BOUNCER_KEY_caddy: ${CROWDSEC_BOUNCER_KEY}
volumes:
- ./config:/etc/crowdsec
- ./data:/var/lib/crowdsec/data
- /srv/docker/stacks/caddy/logs:/var/log/caddy:ro
- /srv/docker/stacks/authelia/log:/var/log/authelia:ro
networks:
- homelab_net
networks:
homelab_net:
external: true
| Block | Bedeutung |
|---|---|
image: crowdsecurity/crowdsec:latest |
CrowdSec pflegt leider keinen stabilen Major-Tag wie caddy:2. :latest ist der empfohlene Stable-Tag. Mit Poll for Updates an, Auto-Update aus in Komodo siehst du neue Versionen und entscheidest selbst wann du deployst |
COLLECTIONS |
Vier Bundles: Caddy-Parser + HTTP-Scenarios, CVE-Patterns für bekannte Web-Exploits, Authelia-Parser + Brute-Force-Erkennung, Whitelist für bekannte gute Crawler (Googlebot etc.) |
BOUNCER_KEY_caddy |
Wird beim ersten Start als Bouncer mit Namen caddy registriert |
./config + ./data |
Konfiguration und Datenbank – persistiert über Updates. Die acquis.yaml aus Schritt 6 liegt in ./config und landet damit unter /etc/crowdsec. ./data ist Pflicht seit CrowdSec 1.7 |
Caddy-Logs + Authelia-Logs (:ro) |
Absoluter Pfad, weil diese Stacks in anderen Verzeichnissen liegen. Read-only |
Kein ports: |
CrowdSec ist nur im internen Docker-Netz erreichbar; Caddy spricht es unter http://crowdsec:8080 an |
Warum keine SSH/Linux-Collection?
Übliche CrowdSec-Anleitungen werfen
crowdsecurity/sshdmit rein, um SSH-Brute-Force zu erkennen. In diesem Setup ist Port 22 seit Artikel 05 öffentlich nicht erreichbar – SSH läuft nur über Tailscale. Ein SSH-Parser auf einem Log, das öffentlich niemand mehr befüllen kann, ist totes Gewicht.
6. .env
# Pre-shared Bouncer-Key (siehe Schritt 3)
# Identisch mit CROWDSEC_API_KEY in der .env des caddy-Stacks
CROWDSEC_BOUNCER_KEY=hier-den-openssl-key-aus-schritt-3-einsetzen
chmod 600 /srv/docker/stacks/crowdsec/.env
Der Schlüssel ist das Login zwischen Caddy und CrowdSec. Wer ihn hat, kann beliebige IPs sperren oder freigeben. Verlust ist kein Drama – neuen erzeugen, in beiden
.env-Dateien austauschen, beide Stacks redeployen. Trotzdem genauso behandeln wie das Authelia-JWT-Secret aus Artikel 09.
7. acquis.yaml anlegen
COLLECTIONS sagt CrowdSec wie es Logs parsen soll. Die acquis.yaml sagt wo die Logs liegen. Ohne diese Datei startet CrowdSec zwar – aber es liest keine einzige Log-Zeile und schlägt nie an. Das ist der häufigste Fehler bei CrowdSec-Docker-Setups.
Die Datei muss vor dem ersten Deploy manuell angelegt werden. Sie gehört ins config-Verzeichnis, das CrowdSec als /etc/crowdsec einhängt:
mkdir -p /srv/docker/stacks/crowdsec/config
nano /srv/docker/stacks/crowdsec/config/acquis.yaml
Inhalt:
---
filenames:
- /var/log/caddy/*.log
labels:
type: caddy
---
filenames:
- /var/log/authelia/*.log
labels:
type: authelia
---
Mit Strg + X, Y, Enter speichern.
Zwei Blöcke, getrennt durch ---. Der erste beobachtet alle .log-Dateien unter /var/log/caddy/ (auch rotierte Dateien wie access.log.001) und schickt sie durch den Caddy-Parser. Der zweite macht dasselbe für Authelia.
Wenn du Artikel 09 übersprungen hast
Dann lass den zweiten Block einfach weg. Falls du Authelia später nachrüstest, fügst du ihn dann hinzu und machst einen Stack-Redeploy.
Caddy-Log-Format muss JSON sein
Der CrowdSec-Caddy-Parser erwartet JSON. Im
(public)-Snippet aus Artikel 07 ist das bereits eingestellt (format json). Falls du dort etwas verändert hast, wird der Parser nichts erkennen.
8. Erstmals deployen
Poll for Updates: on
Auto Update: off
Deploy klicken.
Logs prüfen (Komodo → Stack crowdsec → Logs):
level=info msg="CrowdSec ..."
level=info msg="Adding file /var/log/caddy/access.log to filelist"
level=info msg="Adding file /var/log/authelia/authelia.log to filelist"
level=info msg="loaded N parsers, N scenarios"
level=info msg="CrowdSec Local API listening on 0.0.0.0:8080"
Collections prüfen:
docker exec crowdsec cscli collections list
Erwartung: Vier Einträge (crowdsecurity/caddy, crowdsecurity/http-cve, LePresidente/authelia, crowdsecurity/whitelist-good-actors), Status enabled.
Bouncer-Registrierung prüfen:
docker exec crowdsec cscli bouncers list
Erwartung: Eine Zeile caddy mit valid: true. Die Spalte Last Pull ist noch leer – Caddy hat sich noch nicht verbunden. Das passiert im nächsten Schritt.
Wenn eine Collection nicht installiert wurde (Netz-Hänger, Hub offline): Stack einmal redeployen, oder im Container:
docker exec crowdsec cscli hub update && docker exec crowdsec cscli hub upgrade
9. Caddy einbinden
Jetzt das Stück, das in Artikel 07 vorbereitet wurde: zwei kleine Edits im Caddyfile, eine Zeile in der .env, ein Stack-Redeploy.
9.1 Caddy-.env ergänzen
Im Stack caddy → .env-Tab:
CROWDSEC_API_KEY=hier-den-gleichen-key-wie-im-crowdsec-stack-einsetzen
Exakt derselbe Wert wie CROWDSEC_BOUNCER_KEY im crowdsec-Stack.
9.2 Globalen CrowdSec-Block ins Caddyfile
Im Caddyfile, im globalen Options-Block ganz oben:
{
email {$CADDY_EMAIL}
order crowdsec first
crowdsec {
api_url http://crowdsec:8080
api_key {$CROWDSEC_API_KEY}
ticker_interval 15s
}
}
| Direktive | Bedeutung |
|---|---|
order crowdsec first |
Erzwingt, dass die IP-Prüfung vor allen anderen Handlern läuft. Pflicht – gehört zwingend in den globalen Block. |
api_url |
Service-Name crowdsec, Port 8080 – beide Container im homelab_net |
api_key |
Wird aus der .env eingesetzt. {$VAR} ist Caddys Syntax dafür |
ticker_interval 15s |
Wie oft der Bouncer neue Decisions abholt. Default wäre 60s; mit 15s reagierst du schneller |
9.3 crowdsec-Direktive ins (public)-Snippet
Im (public)-Snippet direkt unter dem Snippet-Header:
(public) {
crowdsec
encode zstd gzip
log {
output file /var/log/caddy/access.log {
roll_size 10MiB
roll_keep 5
}
format json
}
header {
Strict-Transport-Security "max-age=31536000;"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
}
Jede Site, die import public macht, durchläuft jetzt vor dem Reverse-Proxy den crowdsec-Handler. Gebannte IPs bekommen 403 Forbidden, alles andere geht durch wie vorher.
roll_size 10MiB / roll_keep 5 – Log-Rotation: bei 10 MB wird rotiert, maximal 5 alte Dateien. Ohne Rotation wächst die Datei auf einem öffentlichen Server schnell an.
9.4 Caddy-Stack neu deployen
Weil sich die .env geändert hat, reicht kein Reload – wir brauchen einen vollen Redeploy. In Komodo: Stack caddy → Deploy.
Warum Redeploy und nicht nur Caddy-Reload?
.env-Variablen werden nur beim Container-Start eingesetzt, nicht bei einem Reload. Ohne Redeploy bleibt{$CROWDSEC_API_KEY}ein leerer String, und der Bouncer kann sich nicht authentifizieren. Der Redeploy dauert drei Sekunden – Caddy holt seine Zertifikate aus dem/data-Volume und ist sofort wieder am Netz.
Logs nach dem Redeploy:
{"level":"info","logger":"crowdsec","msg":"initializing streaming bouncer"}
{"level":"info","logger":"crowdsec","msg":"first decisions fetched"}
cscli bouncers list zeigt jetzt für caddy auch eine aktuelle Last Pull-Zeit. Wenn ja – die Verbindung steht.
10. Funktionstest mit fremder IP
Wir lösen den Schutz einmal absichtlich aus, ohne einen echten Angriff simulieren zu müssen.
Schritt 1: Eine IP wählen, von der aus du testen kannst. Smartphone ins Mobilfunknetz schalten (WLAN aus), auf ifconfig.me die externe IP ablesen – nennen wir sie 203.0.113.42.
Schritt 2: Auf dem Server einen Ban setzen:
docker exec crowdsec cscli decisions add --ip 203.0.113.42 --duration 5m --reason "test"
Schritt 3: Mit dem Smartphone (im Mobilfunknetz) deine Test-Subdomain aufrufen.
Erwartung: 403 Forbidden – innerhalb von maximal 15 Sekunden nach dem decisions add.
Schritt 4: Ban wieder aufheben:
docker exec crowdsec cscli decisions delete --ip 203.0.113.42
Smartphone-Browser neu laden – die Seite kommt zurück. (Im Zweifel den Privat-Modus nutzen, damit kein Cache stört.)
Wenn das funktioniert hat: Der Bouncer ist aktiv, CrowdSec → Caddy → Browser ist eine geschlossene Kette.
Warum nicht einfach falsches Authelia-Passwort eintippen?
Authelia hat sein eigenes Rate-Limiting (
regulation). Du wirst zuerst von Authelia gebannt (Account-Sperre), bevor du genug Versuche für einen CrowdSec-Trigger zusammen hast. Der Test von einer fremden IP ist sauberer und definitiver.
11. cscli – die wichtigsten Befehle für den Alltag
# Wer ist gerade gebannt?
docker exec crowdsec cscli decisions list
# Was hat zur Ban-Entscheidung geführt?
docker exec crowdsec cscli alerts list
# Eine IP manuell bannen oder freigeben
docker exec crowdsec cscli decisions add --ip 1.2.3.4 --duration 4h --reason "manuell"
docker exec crowdsec cscli decisions delete --ip 1.2.3.4
# Bouncer-Status: wer hat sich wann Decisions geholt?
docker exec crowdsec cscli bouncers list
# Wie viele Log-Zeilen werden geparst, wie viele Bouncer-Anfragen?
docker exec crowdsec cscli metrics
# Hub-Updates ziehen (Parser, Scenarios, CVE-Patterns)
docker exec crowdsec cscli hub update && docker exec crowdsec cscli hub upgrade
Wenn
decisions listplötzlich tausende Einträge zeigtDas ist Absicht – das sind die Community-Decisions aus Schritt 12. Deine eigenen Bans erkennst du am Reason, z. B.
LePresidente/authelia-bffür Authelia-Brute-Force.
12. Die Community-Blocklist aktivieren
Bis hierhin schützt CrowdSec dich auf Basis deiner eigenen Logs. Das wirklich starke Feature ist die Community-Blocklist: IPs, die anderswo schon auffällig waren, werden bei dir präventiv geblockt.
Dafür einmalig bei der CrowdSec-Console registrieren:
Schritt 1: Unter app.crowdsec.net Account anlegen (kostenlos, E-Mail genügt).
Schritt 2: Security Engines → Add Security Engine → Enrollment-Key kopieren.
Schritt 3: Auf dem Server:
docker exec crowdsec cscli console enroll --name homelab DEIN-ENROLLMENT-KEY
Schritt 4: Im Browser auf der Console: Accept Enrollment klicken.
Schritt 5: Stack in Komodo neu Deployen (kurzer Restart, damit die Verbindung aktiv wird).
Prüfen:
docker exec crowdsec cscli capi status
Erwartung: You can successfully interact with Central API (CAPI).
Ab jetzt holt CrowdSec mehrmals täglich Community-Decisions. Ein paar Minuten später solltest du in cscli decisions list tausende Einträge sehen – das sind die globalen Banlists.
Datenschutz – was wird geteilt?
CrowdSec sendet anonymisierte Signaturen deiner Alerts an die zentrale API – Meldungen der Form „IP X hat Pfad Y attackiert". Keine Logs, keine Inhalte, keine Nutzer-Daten. Wer das nicht will, kann diesen Schritt überspringen – CrowdSec bleibt dann ein rein lokaler Schutz.
13. Die eigene IP whitelisten
Wenn du dich von zu Hause regelmäßig bei Authelia einloggst und mal das Passwort vertippst, kannst du dich selbst bannen. Die whitelist-good-actors-Collection schützt bekannte Crawler wie Googlebot, aber nicht dich.
CrowdSec liest Whitelist-Regeln aus dem Verzeichnis config/parsers/s02-enrich/. Per SSH (das Verzeichnis ggf. zuerst anlegen):
mkdir -p /srv/docker/stacks/crowdsec/config/parsers/s02-enrich
nano /srv/docker/stacks/crowdsec/config/parsers/s02-enrich/whitelists.yaml
Inhalt:
name: martin/whitelist-homeip
description: "Whitelist eigene Heim-IP"
whitelist:
reason: "Eigene IP – nie bannen"
ip:
- "203.0.113.7"
cidr:
- "198.51.100.0/24"
203.0.113.7 durch deine wirkliche externe IP ersetzen (auf ifconfig.me nachsehen). Stack einmal redeployen, damit die Datei greift.
Test:
docker exec crowdsec cscli decisions add --ip <deine-IP> --reason "selftest"
docker exec crowdsec cscli decisions list
Die Decision sollte gar nicht erscheinen – die Whitelist hat sie vorher aussortiert.
Bei dynamischer Heim-IP
Bei den meisten deutschen Providern wechselt die IP alle 24 Stunden. Pragmatische Alternative: Tailscale läuft eh – wenn du von zu Hause auf Authelia gehst, geh über den
100.x.x.x-Tailscale-Hostnamen statt über die öffentliche Subdomain. Dann ist deine ISP-IP gar nicht erst beteiligt.
14. Web-Oberfläche: crowdsec-web-ui (optional)
cscli decisions list reicht für den täglichen Betrieb. Wer lieber eine grafische Übersicht will – Alerts, aktive Bans, Angriffstypen, Geo-Herkunft – bekommt das mit crowdsec-web-ui: eine schlanke React-App, die direkt gegen die CrowdSec-API spricht. Ein Container, keine externe Datenbank, aktiv gepflegt.
14.1 Machine Account anlegen
Die Web-UI authentifiziert sich über ein Machine-Konto – das ist ein anderes Konzept als der Bouncer-Key. Ein Machine-Konto hat Lese- und Schreibzugriff auf die LAPI (es kann z. B. Bans aus der UI heraus entfernen).
# Passwort generieren
openssl rand -hex 32
# Machine-Konto anlegen
docker exec crowdsec cscli machines add crowdsec-web-ui --password <generiertes-passwort> -f /dev/null
Das Flag -f /dev/null verhindert, dass cscli die Credentials-Datei des CrowdSec-Containers überschreibt.
14.2 compose.yaml erweitern
Den crowdsec-ui-Service zum bestehenden Stack hinzufügen:
name: crowdsec
services:
crowdsec:
image: crowdsecurity/crowdsec:latest
container_name: crowdsec
restart: unless-stopped
env_file: .env
environment:
COLLECTIONS: "crowdsecurity/caddy crowdsecurity/http-cve LePresidente/authelia crowdsecurity/whitelist-good-actors"
BOUNCER_KEY_caddy: ${CROWDSEC_BOUNCER_KEY}
volumes:
- ./config:/etc/crowdsec
- ./data:/var/lib/crowdsec/data
- /srv/docker/stacks/caddy/logs:/var/log/caddy:ro
- /srv/docker/stacks/authelia/log:/var/log/authelia:ro
networks:
- homelab_net
crowdsec-ui:
image: ghcr.io/theduffman85/crowdsec-web-ui:latest
container_name: crowdsec-ui
restart: unless-stopped
environment:
- CROWDSEC_URL=http://crowdsec:8080
- CROWDSEC_USER=crowdsec-web-ui
- CROWDSEC_PASSWORD=${CROWDSEC_UI_PASSWORD}
- CROWDSEC_LOOKBACK_PERIOD=7d
- CROWDSEC_REFRESH_INTERVAL=30s
volumes:
- ./ui-data:/app/data
networks:
- homelab_net
networks:
homelab_net:
external: true
In der .env ergänzen:
CROWDSEC_BOUNCER_KEY=...
CROWDSEC_UI_PASSWORD=<das-generierte-passwort-von-oben>
14.3 Caddy-Route anlegen
Per SSH ins Caddyfile:
crowdsec.deine-domain.de {
import public
import auth
reverse_proxy crowdsec-ui:3000
}
Die UI läuft hinter Authelia – kein Login in der App selbst nötig.
Caddy neu laden:
docker exec caddy caddy validate --config /etc/caddy/Caddyfile
docker exec caddy caddy reload --config /etc/caddy/Caddyfile
Stack crowdsec in Komodo neu Deployen.
crowdsec-web-ui hat keine eigene Authentifizierung – bewusstes Design der Entwickler.
import authim Caddy-Block ist daher Pflicht, nicht optional.
15. Optional: AppSec – Schutz vor SQLi, XSS und bekannten CVE-Exploits
Beim ersten Lesen ruhig überspringen. Mit den bisherigen Schritten hast du einen vollwertigen IP-Reputations-Schutz. AppSec ist eine zusätzliche Schicht, die man später nachrüsten kann.
Bis hierhin sperrt CrowdSec IPs. Wer aber bisher unauffällig war, kommt mit jedem Request durch – Caddy schaut nicht in den Request rein. AppSec dreht das um: Es prüft jeden Request vor der Weiterleitung an die App. SQLi, XSS, Path Traversal, bekannte CVE-Exploits werden direkt blockiert.
15.1 AppSec-Collections nachinstallieren
In der compose.yaml des crowdsec-Stacks die COLLECTIONS-Zeile erweitern:
COLLECTIONS: "crowdsecurity/caddy crowdsecurity/http-cve LePresidente/authelia crowdsecurity/whitelist-good-actors crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules"
15.2 AppSec-Datasource in der acquis.yaml
Einen dritten Block anhängen:
---
appsec_config: crowdsecurity/appsec-default
labels:
type: appsec
listen_addr: 0.0.0.0:7422
source: appsec
15.3 Caddyfile erweitern
Im globalen Block:
crowdsec {
api_url http://crowdsec:8080
api_key {$CROWDSEC_API_KEY}
ticker_interval 15s
appsec_url http://crowdsec:7422
}
Im (public)-Snippet direkt unter crowdsec:
(public) {
crowdsec
appsec
encode zstd gzip
...
}
Reihenfolge wichtig: Erst crowdsec (IP-Check – schnell), dann appsec (Inhaltsprüfung – aufwändiger). Bekannte böse IPs filtern wir raus, bevor sie durch die WAF müssen.
15.4 Beide Stacks neu deployen
Stack crowdsec redeployen (für den neuen acquis-Block), Stack caddy redeployen (für die neue appsec-Direktive).
AppSec und False Positives
Die
appsec-virtual-patching-Collection ist eng gefasst: konkrete CVE-Exploits, kaum Bauchgefühl. False-Positive-Risiko nahe null. Dieappsec-generic-rulesist aggressiver – sie kann Admin-Backends, die Sonderzeichen in URLs erwarten, anders bewerten. Empfehlung: mitvirtual-patchingstarten,generic-rulesnur dazuholen, wenn du Zeit zum Tunen hast.cscli alerts listzeigt dir bei Problemen, welche Regel getriggert hat.
16. Wartung
CrowdSec ist erfreulich pflegeleicht – zwei Dinge regelmäßig tun:
Hub-Updates (Parser, Scenarios, CVE-Patterns) – etwa monatlich:
docker exec crowdsec cscli hub update
docker exec crowdsec cscli hub upgrade
Läuft beim Container-Start zwar automatisch, aber wenn der Container monatelang durchläuft, passiert nichts. Ein manueller Lauf alle paar Wochen kostet nichts.
Image-Updates – Komodo zeigt sie durch Poll for Updates an. Bei neuer Version: Stack redeployen. Der ./data-Mount behält die Datenbank mit Bouncer-Registrierung und Decisions – nach dem Upgrade läuft alles weiter.
Eigene Whitelist-IP – wann immer dein Provider die IP wechselt und du es merkst (meist erst, wenn du dich aus Versehen selbst bannst). Datei aus Schritt 13 editieren, Stack redeployen.
Und jetzt?
Das war's mit Phase 2 – Infrastruktur. Du hast jetzt:
- Tailscale für sicheren Admin-Zugang ohne offene SSH-Ports (Artikel 05)
- Komodo für Docker-Verwaltung im Browser (Artikel 06)
- Caddy als einzigen kontrollierten öffentlichen Eingang mit HTTPS (Artikel 07)
- Mail-Relay für App-Benachrichtigungen (Artikel 08)
- Authelia als 2FA-Login-Schicht vor persönlichen Apps (Artikel 09)
- CrowdSec als IP-Reputation- und Angriffserkennungs-Layer (dieser Artikel)
Jede neue App in Phase 3 hängt sich in dieses Geflecht ein, ohne dass du an der Infrastruktur etwas ändern musst. Sie importiert in Caddy je nach Zugriffsbedarf public oder public + auth, sie nutzt den Mail-Relay für Benachrichtigungen, und sie wird automatisch von CrowdSec mitgeschützt – weil der Bouncer in Caddy davor sitzt.
Im nächsten Artikel kommt der App-Baukasten – der konzeptionelle Übergang von Infrastruktur zu Apps.
👉 Nächster Artikel: 11. App-Baukasten verstehen und nutzen
Discussion