Mit Docker lassen sich sehr leicht neue Container auf einem Host erstellen. Sollen aber mehrere Container über dem Port 80 (HTTP) nach außen kommunizieren, so kann es etwas problematisch werden, da dieser Port nur einmal auf dem Server zur Verfügung steht. Wir benutzen Traefik und erweitern es mit CrowdSec um diese Thematik anzugehen.
Diese Anleitung ist eine überarbeitete Variante von Christians Version und erweitert Traefik zusätzlich um das Sicherheitssuite CrowdSec.
Diese Anleitung wird nicht weiter gepflegt. Es gibt eine neue FullStack-Anleitung:
0. Versionierung
| Datum | Änderung |
|---|---|
| 25.05.2023 | Hinweis auf neue Anleitung |
| 29.12.2022 | Nützliches hinzugefügt als Community Inhalt – X Real IP hinzugefügt |
| 28.12.2022 | Crontab nach oben geschoben Verweis auf Authelia hinzugefügt |
| 23.12.2022 | Traefik um statische IP-Adresse im CrowdSec Netzwerk erweitert |
| 22.12.2022 | Überprüfen der Anleitung Traefik: – Docker Network überarbeitet Crowdsec: – Docker Network überarbeitet Statische IPs vergeben: crowdsec -> 172.31.0.2 crowdsec-bouncer-traefik -> 172.31.0.3 Es handelt sich hier um elementare Änderungen. Die Änderungen können auch bereits laufende Systeme adaptiert werden. Hierzu Traefik und crowdsec stoppen und den jeweiligen Netzwerkteil in allen docker-compose.yml anpassen. Crontab hinzugefügt (Danke an @ice-cue) Testen der Anleitung auf einer neuen Instanz |
| 12.08.2022 | traefik.yml: – unötigen Code entfernt. – Log angepasst dynamic_conf.yml – deprecated funktion auskommentiert |
| 10.08.2022 | Erfolgskontrolle der Anleitung weiter nach hinten geschoben. 4.3.6. -> 5.1. |
Korrektur der dynamic_conf.yml: secHeder zu secHeaders | |
| 09.08.2022 | Name des CertResolver von ‘letsEncrypt’ auf ‘http’ geändert Anleitung ist nun vollständig auf ältere Anleitungen kompatibel |
| Abschnitt 6 hinzugefügt | |
| Kompatibilität zu alten Anleitungen verbessert | |
| Optimierung der docker-compose.yml von Traefik Netzwerk ‘proxy’ wird automatisch erstellt | |
| 08.08.2022 | Fehler in der docker-compose.yml von Traefik behoben- /var/log/crowdsec/traefik/:/var/log/traefik/ |
| Information bei Voraussetzungen ergänzt | |
| Pfad unter “3.2. Konfiguration anpassen” korrigiert | |
| Befehl um htpasswd-Passwort zu erstellen geändert | |
| Veröffentlichung |
Hinweis
Seit dem 25.05.2023 gibt es unter steht eine neue Anleitung zur Verfügung!
1. Was ist das Ziel dieser Anleitung?
Grundsätzlich erweitert diese Anleitung die ursprüngliche Anleitung von Christian. Es werden ein paar Dinge optimiert und es gilt weiterhin der Anspruch euch eine Anleitung zu schreiben, dass Ihr eure Applikationen möglichst sicher nutzen könnt! In dieser Anleitung werden wir:
- Traefik v2 installieren und konfigurieren
- Crowdsec installieren und konfigurieren
- Traefik via Crowdsec überwachen
- Wissen, wie ihr neue Anwendungen zu Traefik hinzufügt.
Achtung: Nach dieser Anleitung ist das Hinzufügen von Anwendungen in Traefik nicht mehr vollständig kompatibel zu Christians Anleitung. Dafür etwas kürzer und einfacher.
2. Voraussetzung
- Docker mit Docker Compose installiert (Anleitung für Ubuntu / Debian) (Wichtig!)
- htpasswd installiert (
sudo apt update && sudo apt install apache2-utils)
3. Traefik
3.1. Verzeichnisse / Dateien anlegen
Als erstes legen wir uns ein Verzeichnis für Traefik an und wechsel in das Verzeichnis:
mkdir -p /opt/containers/traefik
cd /opt/containers/traefik
Anschließend erzeugen wir uns noch Datein und Ordner, welche wir später noch benötigen:
mkdir -p /opt/containers/traefik/data
touch /opt/containers/traefik/data/acme_letsencrypt.json
chmod 600 /opt/containers/traefik/data/acme_letsencrypt.json
touch /opt/containers/traefik/data/traefik.yml
3.2. Konfiguration anpassen
Nun bearbeiten wir die Datei traefik.yml:
Dabei ist wichtig, dass in der .yml nur Leerzeichen und keine Tabs benutzen werden dürfen!
nano /opt/containers/traefik/data/traefik.yml
api:
dashboard: true
certificatesResolvers:
http:
acme:
email: "meine@email.de"
storage: "acme_letsencrypt.json"
httpChallenge:
entryPoint: http
entryPoints:
http:
address: ":80"
http:
redirections:
entryPoint:
to: "https"
scheme: "https"
https:
address: ":443"
global:
checknewversion: true
sendanonymoususage: false
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: "proxy"
file:
filename: "./dynamic_conf.yml"
watch: true
providersThrottleDuration: 10Code-Sprache: CSS (css)
# Statische Traefik-Konfigurationsdatei
# https://doc.traefik.io/traefik/getting-started/configuration-overview/#the-static-configuration
# https://doc.traefik.io/traefik/reference/static-configuration/cli/
api:
dashboard: true # Aktivieren des Dashboard
# Certificate Resolver
# Diese sind für den Abruf von Zertifikaten von einem ACME-Server zuständig
# https://doc.traefik.io/traefik/https/acme/#certificate-resolvers
certificatesResolvers:
http:
acme:
email: "meine@email.de" # E-Mail-Adresse für die Registrierung
storage: "acme_letsencrypt.json" # Datei für die Speicherung von Zertifikate (Ich weiche hier bewusst von dem "Standard": acme.json ab)
httpChallenge:
entryPoint: http
# EntryPoints
# EntryPoints sind die Netzwerk-Eingangspunkte in Traefik. Sie definieren den Port, der die Pakete empfängt.
# https://doc.traefik.io/traefik/routing/entrypoints/
entryPoints:
http:
address: ":80" # Erstellen des Einstiegspunkt für HTTP (Port 80)
http:
redirections: # Weiterleitung von HTTP auf HTTPS (Port 80 zu Port 443).
entryPoint:
to: "https" # Das Ziel
scheme: "https" # Umleitungszielschema
https:
address: ":443" # Erstellen des Einstiegspunkt für HTTPS (Port 443)
global:
checknewversion: true # In regelmäßigen Abständen prüfen, ob eine neue Version veröffentlicht wurde.
sendanonymoususage: false # Regelmäßige Übermittlung anonymer Nutzungsstatistiken.
providers:
docker:
endpoint: "unix:///var/run/docker.sock" # Den UNIX Docker socket beobachten
exposedByDefault: false # Nur Container ausstellen, die explizit aktiviert sind (mit dem Label traefik.enabled)
network: "proxy" # Standardnetzwerk, das für Verbindungen zu allen Containern verwendet wird.
file:
filename: "./dynamic_conf.yml" # Link zur dynamischen Konfiguration
watch: true # Achten auf Änderungen
providersThrottleDuration: 10 # Frequenz in welchen Abständen die Konfiguration nachgeladen wirdCode-Sprache: PHP (php)
Notwendige Anpassungen (unkommentierte Version)
- Zeile 7: Anpassen an die eigene Email-Adresse.
Informationen
- Ich verwende in dieser Variante bewusst nicht
acme.jsonals Dateiname. Diese Variante soll am Ende nicht nur Zertifikate via HTTP-Challange abrufen können sondern auch vorbereitet sein dies via DNS-Challange (damit sind Wildcard-Zertifikate möglich) zu machen. So das wir uns für jeden Container seperat entscheiden können welche Challange wir nutzen bzw. benötigen. - Mit ein Grund für Traefik ist, dass am Ende die Anfrage via HTTPS gehen soll. Um nun nicht jedem einzelnen Container händisch die Weiterleitung auf HTTPS mitgeben zu müssen machen wir das hier einfach als allgemeine Regel.
3.3. Anlegen der dynamischen Konfiguration
Jetzt legen wir noch die dynamische Konfiguration an:
nano /opt/containers/traefik/data/dynamic_conf.yml
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
http:
middlewares:
traefikAuth:
basicAuth:
users:
- "benutzer:passworthash"
default:
chain:
middlewares:
- default-security-headers
- gzip
secHeaders:
chain:
middlewares:
- default-security-headers
- gzip
default-security-headers:
headers:
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
frameDeny: true
# Deprecated
# sslRedirect: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
gzip:
compress: {}Code-Sprache: PHP (php)
# TLS
# Hier werden alle notwendigen Einstellungen für das Zertifikat getroffen.
# In Kombination mit den Einstellungen unter http.middlewares.default-security-headers bekommen wir ein A+ Zertifikat.
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
# Middlewares
# Optionale Optimierungen, die bei jeder Anfrage vorgenommen werden sollen bevor diese an den Zielcontainer geleitet wird.
http:
middlewares:
# Eine grundlegende Authentifizierungs-Middleware, um das Traefik-Dashboard via htpasswd zu schützen
# Um die Authentifizierung für einen Container zu nutzen können wir "traefik.http.routers.definierteRoute.middlewares=traefikAuth@file" nutzen
traefikAuth:
basicAuth:
users:
- "benutzer:passworthash"
# Empfohlene Standard-Middleware für die meisten Dienste
# Hinzufügbar via "traefik.http.routers.definierteRoute.middlewares=default@file"
# Equivalent mit "traefik.http.routers.definierteRoute.middlewares=default-security-headers@file,gzip@file"
# Die Liste kann hier auch beliebig erweitert werden
default:
chain:
middlewares:
- default-security-headers
- gzip
# Kompatibilität zu alten Anleitungen. Damit kann auch wieder "traefik.http.routers.definierteRoute.middlewares=secHeader@file"
secHeaders:
chain:
middlewares:
- default-security-headers
- gzip
# Standard Header
default-security-headers:
headers:
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
frameDeny: true
# Deprecated
# sslRedirect: true
#HSTS Configuration
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
# Gzip Kompression
gzip:
compress: {}Code-Sprache: PHP (php)
3.4. Dashboard mit Passwort schützen
Wenn das Dashboard aktiviert wurde ist dies erst mal ungeschützt. Das Dashboard zeigt “nur” Informationen über die laufenden Dienste an. Das sind Informationen, welche wir nicht unbedingt mit der gesamten Maße teilen möchten. Deswegen schützen wir das Dashboard via htpasswd. Die notwendige Middleware dazu haben wir bereits in der dynamischen Konfiguration unter traefikAuth schon getroffen. Wir müssen uns nur noch einen Benutzernamen überlegen und ein Wunschpasswort dazu hashen:
echo $(htpasswd -nb <user> '<password>')
# Zum Beispiel:
# echo $(htpasswd -nb jonathan 'supersicher')
# Ausgabe: jonathan:$$apr1$$J8vBlNIm$$lSwLv9iGa8KcCct3EyLD41
# Sollte es an dieser Stelle zu Problemen kommen kann man sich auch das Passwort auf Webseiten
# wie zum Beispiel: https://www.redim.de/blog/passwortschutz-mit-htaccess-einrichten generieren lassen.Code-Sprache: PHP (php)
Nun ergänzen wir die dynamische Konfiguration um den eben generierte Benutzername/Passwort-Information:
nano /opt/containers/traefik/data/dynamic_conf.yml
# [...]
http:
middlewares:
traefikAuth:
basicAuth:
users:
- "benutzer:passworthash"
# [...]Code-Sprache: CSS (css)
# [...]
http:
middlewares:
traefikAuth:
basicAuth:
users:
- "jonathan:$$apr1$$J8vBlNIm$$lSwLv9iGa8KcCct3EyLD41"
# [...]Code-Sprache: PHP (php)
3.5. Docker-Compose.yml anlegen
Nun legen wir die docker-compose.yml an:
nano /opt/containers/traefik/docker-compose.yml
version: '3.9'
services:
traefik:
container_name: traefik
image: traefik:latest
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme_letsencrypt.json:/acme_letsencrypt.json
- ./data/dynamic_conf.yml:/dynamic_conf.yml
labels:
- "com.centurylinklabs.watchtower.enable=true"
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`traefik.meinedomain.de`)"
- "traefik.http.routers.traefik.middlewares=traefikAuth@file,default@file"
- "traefik.http.routers.traefik.tls=true"
- "traefik.http.routers.traefik.tls.certresolver=http"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.services.traefik.loadbalancer.sticky.cookie.httpOnly=true"
- "traefik.http.services.traefik.loadbalancer.sticky.cookie.secure=true"
- "traefik.docker.network=proxy"
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
proxy:
hostname: traefik
ports:
- "80:80"
- "443:443"
networks:
proxy:
name: proxy
driver: bridge
attachable: trueCode-Sprache: PHP (php)
version: '3.9'
services:
traefik:
container_name: traefik
image: traefik:latest
volumes:
# Traefik mit der Zeit vom Server syncronisieren
- /etc/localtime:/etc/localtime:ro
# Lesezugriff auf den UNIX Docker socket
- /var/run/docker.sock:/var/run/docker.sock:ro
# Traefik-Konfiguration bereitstellen
- ./data/traefik.yml:/traefik.yml:ro
# Datei mit Zertifikaten bereitstellen
- ./data/acme_letsencrypt.json:/acme_letsencrypt.json
# Datei mit dynamischer Konfiguration bereitstellen
- ./data/dynamic_conf.yml:/dynamic_conf.yml
labels:
# Traefik durch Watchtower aktualisieren lassen
# https://stage.goneuland.de/docker-images-automatisiert-aktualisieren-mit-watchtower/
- "com.centurylinklabs.watchtower.enable=true"
# Traefik für Traefik aktivieren
- "traefik.enable=true"
# Als Einstiegspunkt wählen wir direkt HTTPS
- "traefik.http.routers.traefik.entrypoints=https"
# Domain anpassen unter der Traefik erreichbar sein soll.
- "traefik.http.routers.traefik.rule=Host(`traefik.meinedomain.de`)"
# Middlewares definieren, welche verwendet werden sollen. Hier die Authentifizierung via htpasswd + alle die unter default definiert sind.
- "traefik.http.routers.traefik.middlewares=traefikAuth@file,default@file"
# SSL Zertifikat abrufen
- "traefik.http.routers.traefik.tls=true"
# Definierten Zertifikat Resolver aus traefik.yml wählen
- "traefik.http.routers.traefik.tls.certresolver=http"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.services.traefik.loadbalancer.server.port=80"
- "traefik.http.services.traefik.loadbalancer.sticky.cookie.httpOnly=true"
- "traefik.http.services.traefik.loadbalancer.sticky.cookie.secure=true"
# Traefik dem Proxy-Netzwerk hinzufügen.
- "traefik.docker.network=proxy"
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
proxy:
hostname: traefik
ports:
# Ports definieren, welche durch Traefik gemanaget werden.
- "80:80"
- "443:443"
networks:
proxy:
name: proxy
driver: bridge
attachable: trueCode-Sprache: PHP (php)
Notwendige Anpassungen in der unkommentierten Version
- Zeile 16: Auf eigene Domain anpassen
3.6. Traefik starten
Nun können wir Traefik starten:
docker compose -f /opt/containers/traefik/docker-compose.yml up -d
Wenn ihr nun auf traefik.meinedomain.de geht, solltet ihr folgendes sehen:

Nach dem Login mit eurem oben festgelegten Passwort solltet ihr diese Übersicht sehen:

Hier sind wir jetzt fertig mit der Traefik Konfiguration und Installation.
3.7. Anwendungen hinzufügen
Im Allgemeinen ist es wichtig, dass ihr die Labels hinzufügen:
wordpress:
labels:
# Aktiviert Traefik für diesen Container
- "traefik.enable=true"
# Hier wird der Einstiegspunkt definiert. Da wir eigentlich zu 99% HTTPS nutzen möchten können wir uns HTTP auch sparen.
# Beispielhaft habe ich euch HTTP nochmal auskommentiert hinzugefügt. An dieser Stelle ist keine Weiterleitung zu HTTPS mehr notwenig.
# Die Weiterleitung von HTTP zu HTTPS wurde bereits in der traefik.yml festgelegt
# - "traefik.http.routers.wordpress.entrypoints=http"
# - "traefik.http.routers.wordpress.rule=Host(`wordpress.euredomain.de`)"
- "traefik.http.routers.wordpress-ssl.entrypoints=https"
- "traefik.http.routers.wordpress-ssl.rule=Host(`wordpress.euredomain.de`)"
- "traefik.http.routers.wordpress-ssl.tls=true"
- "traefik.http.routers.wordpress-ssl.tls.certresolver=http"
- "traefik.http.routers.wordpress-ssl.middlewares=default@file"
- "traefik.http.routers.wordpress-ssl.service=wordpress-ssl"
- "traefik.http.services.wordpress-ssl.loadbalancer.server.port=80"
- "traefik.docker.network=proxy"Code-Sprache: PHP (php)
Wichtig ist hier auch, dass unser Service “wordpress-ssl” heißt und dementsprechend die Labels auch alle auf den Namen “wordpress-ssl” angepasst werden müssen. Dies kann aber auch jeder andere Name sein. Muss nur konstant sein.
Ihr müsst immer noch das Netzwerk hinzufügen, mit dem Traefik kommuniziert. Dieses Netzwerk ist im einfachsten Fall bei jeder Anwendung identisch. In diesem Fall also “proxy”.
wordpress:
networks:
- proxy
networks:
proxy:
external: trueCode-Sprache: JavaScript (javascript)
Der Name “proxy” wurde hier auch frei gewählt. Dort könnt ihr auch jeden anderen Namen verwenden. Das Netzwerk wird normalerweise durch die docker-compose.yml generiert. Sollte es das nicht der Fall sein:
docker network create proxy
4. CrowdSec
CrowdSec ist ein kostenloses, quelloffenes und kollaboratives IPS. Mit dem Verhaltensweisen analysiert werden, auf Angriffe reagiert wird und Hinweise in der Community geteilt werden. Es ist sozusagen das neue Fail2Ban.
4.1. Verzeichnisse / Dateien anlegen
Als erstes legen wir uns ein Verzeichnis für Crowdsec an und wechsel in das Verzeichnis:
mkdir -p /opt/containers/crowdsec
cd /opt/containers/crowdsec
Anschließend erzeugen wir uns noch Datein und Ordner, welche wir später noch benötigen:
mkdir -p /opt/containers/crowdsec/{config,data}
touch /opt/containers/crowdsec/.env
4.2. Docker-Compose.yml anlegen
Wir könnten CrowdSec nativ auf unserem Host installieren, allerdings machen wir hier alles mit Docker und auch CrowdSec funktioniert wunderbar mit Docker. In diesem Schritt legen wir uns für CrowdSec die docker-compose.yml an:
nano /opt/containers/crowdsec/docker-compose.yml
version: "3.9"
services:
crowdsec:
container_name: crowdsec
image: crowdsecurity/crowdsec:latest
environment:
PGID: "1000"
COLLECTIONS: "crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/whitelist-good-actors"
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config:/etc/crowdsec
- ./data:/var/lib/crowdsec/data
- /var/log/auth.log:/var/log/auth.log:ro
- /var/log/crowdsec:/var/log/crowdsec:ro
restart: unless-stopped
security_opt:
- no-new-privileges=true
networks:
crowdsec:
ipv4_address: 172.31.0.2
hostname: crowdsec
networks:
crowdsec:
name: crowdsec
driver: bridge
ipam:
config:
- subnet: 172.31.0.0/24
gateway: 172.31.0.1Code-Sprache: JavaScript (javascript)
# Dies entspricht der Anleitung vor dem 22.12.2022
version: "3.9"
services:
crowdsec:
container_name: crowdsec
image: crowdsecurity/crowdsec:latest
environment:
PGID: "1000"
COLLECTIONS: "crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/whitelist-good-actors"
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config:/etc/crowdsec
- ./data:/var/lib/crowdsec/data
- /var/log/auth.log:/var/log/auth.log:ro
- /var/log/crowdsec:/var/log/crowdsec:ro
restart: unless-stopped
security_opt:
- no-new-privileges=true
networks:
- proxy
hostname: crowdsec
networks:
proxy:
external: trueCode-Sprache: PHP (php)
Bis hier her ist das docker-compose.yml nichts besonderes. Wichtig ist, dass wir die GID Berechtigungen gesetzt haben und alle Logs lesen können. Dafür mounten wir:
- /var/log/auth.log:/var/log/auth.log:ro
- /var/log/crowdsec:/var/log/crowdsec:roCode-Sprache: JavaScript (javascript)
Die Umgebungsvariable COLLECTIONS ermöglicht es uns die Vorinstallation von Collections aus dem CrowdSec Hub. Collections sind Bündel von Parsern und Szenarien, die es einfach machen, Dinge für beliebte Dienste einzurichten. Standardmäßig wird der Container mit der Linux-Sammlung ausgeliefert, welche Syslog- und SSH-Protokolle verarbeitet. Wir werden die traefik-Sammlung, die http-cve-Sammlung, die eine Sammlung derzeitiger aktiver CVEs abdeckt, und die whitelist-good-actors-Sammlung hinzufügen, die hauptsächlich CDNs wie Cloudflare abdeckt. Damit stellen wir sicher, dass wir sie nicht versehentlich blockieren und uns von großen Teilen des Internets abschneiden.
4.3. Konfiguration anpassen
Nun starten wir den Container um alle wichtigen Datein generieren zu lassen:
docker compose -f /opt/containers/crowdsec/docker-compose.yml up -d
4.3.1. Acquis.yaml bearbeiten
Nach dem wir den den Container gestartet haben finden wir die Datei config/acquis.yaml und passen diese für unsere Bedürfnisse an:
sudo nano /opt/containers/crowdsec/config/acquis.yaml
filenames:
- /var/log/auth.log
- /var/log/syslog
labels:
type: syslog
---
filenames:
- /var/log/crowdsec/traefik/*.log
labels:
type: traefik
---Code-Sprache: JavaScript (javascript)
4.3.2. Traefik.yml anpassen
Jetzt müssen wir innerhalb Traefik die Ausgabe der Log-Dateien definieren um diese CrowdSec zur Verfügugn zu stellen. Dafür passen wir von Traefik die traefik.yml an. Folgenden Teil kopieren wir uns an das Ende der Datei:
nano /opt/containers/traefik/data/traefik.yml
# [...] Ende der Datei
log:
level: "INFO"
filePath: "/var/log/traefik/traefik.log"
accessLog:
filePath: "/var/log/traefik/access.log"
bufferingSize: 100Code-Sprache: PHP (php)
4.3.3. Traefik docker-compose.yml anpassen
In diesem Schritt ergänzen wir die docker-compose.yml von Traefik um einen Mount für die Logs und das Netzwerk von Crowdsec
nano /opt/containers/traefik/docker-compose.yml
version: '3.9'
services:
traefik:
container_name: traefik
image: traefik:latest
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme_letsencrypt.json:/acme_letsencrypt.json
- ./data/dynamic_conf.yml:/dynamic_conf.yml
- /var/log/crowdsec/traefik/:/var/log/traefik/ # Diese Zeile muss hinzugefügt werden
labels:
- "com.centurylinklabs.watchtower.enable=true"
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`traefik.meinedomain.de`)"
- "traefik.http.routers.traefik.middlewares=traefikAuth@file,default@file"
- "traefik.http.routers.traefik.tls=true"
- "traefik.http.routers.traefik.tls.certresolver=http"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.services.traefik.loadbalancer.sticky.cookie.httpOnly=true"
- "traefik.http.services.traefik.loadbalancer.sticky.cookie.secure=true"
- "traefik.docker.network=proxy"
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
proxy:
crowdsec: # Diese Zeile muss hinzugefügt werden
ipv4_address: 172.31.0.10 # Diese Zeile muss hinzugefügt werden
hostname: traefik
ports:
- "80:80"
- "443:443"
networks:
proxy:
name: proxy
driver: bridge
attachable: true
crowdsec: # Diese Zeile muss hinzugefügt werden
external: true # Diese Zeile muss hinzugefügt werdenCode-Sprache: PHP (php)
# Dies entspricht der Anleitung vor dem 22.12.2022
services:
traefik:
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme_letsencrypt.json:/acme_letsencrypt.json
- ./data/dynamic_conf.yml:/dynamic_conf.yml
- /var/log/crowdsec/traefik/:/var/log/traefik/ # Diese Zeile muss hinzugefügt werdenCode-Sprache: PHP (php)
4.3.4. Traefik neustarten
Um die geänderte Konfiguration zu laden starten wir Traefik erneut:
docker compose -f /opt/containers/traefik/docker-compose.yml up -d --force-recreate
4.3.5. CrowdSec Konfiguration neu laden
Jetzt muss noch die Konfiguration von CrowdSec neu geladen werden, dass er auch auf die von uns definierten Logs zugreifen kann. Dafür muss man den Container nicht neutstarten sondern kann einfach die Konfig neu laden:
docker compose exec -t crowdsec kill -SIGHUP 1
4.4. Traefik Bouncer
CrowdSec ist nun in der Lage die Log-Dateien zu lesen und verdächtige IP-Adressen auf die Ban-Liste zu setzten. Nice! Allerdings in dem aktuellen Zustand wird noch nichts unternommen um den potenziellen Angriff abzuwehren. In CrowdSec sind sogenante Bouncer dafür zuständig. Von diesen Bouncern gibt es sehr viele! Es gibt einen Firewall Bouncer für iptables/nftables, einen Cloudflare Bouncer um die Firewall von Cloudflare zu steueren und es gibt auch einen Traefik Bouncer, was für uns hier interessant ist.
4.4.1. CrowdSec: docker-compose.yml ergänzen
Wir ergänzen CrowdSec um den Traefik Bouncer:
nano /opt/containers/crowdsec/docker-compose.yml
bouncer-traefik:
container_name: crowdsec-bouncer-traefik
image: fbonalair/traefik-crowdsec-bouncer:latest
environment:
CROWDSEC_BOUNCER_API_KEY: ${TRAEFIK_BOUNCER_KEY}
CROWDSEC_AGENT_HOST: crowdsec:8080 # Hier könnte nun auch bei Bedarf die statische IP 172.31.0.2:8080 verwendet werden
restart: unless-stopped
depends_on:
- crowdsec
networks:
crowdsec:
ipv4_address: 172.31.0.3
hostname: crowdsec-bouncer-traefikCode-Sprache: PHP (php)
version: "3.9"
services:
crowdsec:
container_name: crowdsec
image: crowdsecurity/crowdsec:latest
environment:
PGID: "1000"
COLLECTIONS: "crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/whitelist-good-actors"
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config:/etc/crowdsec
- ./data:/var/lib/crowdsec/data
- /var/log/auth.log:/var/log/auth.log:ro
- /var/log/crowdsec:/var/log/crowdsec:ro
restart: unless-stopped
security_opt:
- no-new-privileges=true
networks:
crowdsec:
ipv4_address: 172.31.0.2
hostname: crowdsec
bouncer-traefik:
container_name: crowdsec-bouncer-traefik
image: fbonalair/traefik-crowdsec-bouncer:latest
environment:
CROWDSEC_BOUNCER_API_KEY: ${TRAEFIK_BOUNCER_KEY}
CROWDSEC_AGENT_HOST: crowdsec:8080 # Hier könnte nun auch bei Bedarf die statische IP 172.31.0.2:8080 verwendet werden
restart: unless-stopped
depends_on:
- crowdsec
networks:
crowdsec:
ipv4_address: 172.31.0.3
hostname: crowdsec-bouncer-traefik
networks:
crowdsec:
name: crowdsec
driver: bridge
ipam:
config:
- subnet: 172.31.0.0/24
gateway: 172.31.0.1Code-Sprache: PHP (php)
# Dies entspricht der Anleitung vor dem 22.12.2022
bouncer-traefik:
container_name: crowdsec-bouncer-traefik
image: fbonalair/traefik-crowdsec-bouncer:latest
environment:
CROWDSEC_BOUNCER_API_KEY: ${TRAEFIK_BOUNCER_KEY}
CROWDSEC_AGENT_HOST: crowdsec:8080
restart: unless-stopped
depends_on:
- crowdsec
networks:
- proxy
hostname: crowdsec-bouncer-traefikCode-Sprache: PHP (php)
# Dies entspricht der Anleitung vor dem 22.12.2022
version: "3.9"
services:
crowdsec:
container_name: crowdsec
image: crowdsecurity/crowdsec:latest
environment:
PGID: "1000"
COLLECTIONS: "crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/whitelist-good-actors"
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config:/etc/crowdsec
- ./data:/var/lib/crowdsec/data
- /var/log/auth.log:/var/log/auth.log:ro
- /var/log/crowdsec:/var/log/crowdsec:ro
restart: unless-stopped
security_opt:
- no-new-privileges=true
networks:
- proxy
hostname: crowdsec
bouncer-traefik:
container_name: crowdsec-bouncer-traefik
image: fbonalair/traefik-crowdsec-bouncer:latest
environment:
CROWDSEC_BOUNCER_API_KEY: ${TRAEFIK_BOUNCER_KEY}
CROWDSEC_AGENT_HOST: crowdsec:8080
restart: unless-stopped
depends_on:
- crowdsec
networks:
- proxy
hostname: crowdsec-bouncer-traefik
networks:
proxy:
external: trueCode-Sprache: PHP (php)
4.4.2. API-Schlüssel generieren
Nun müssen wir noch einen API-Schlüssel erzeugen in dem wir den Bouncer bei CrowdSec registieren:
docker compose exec -t crowdsec cscli bouncers add bouncer-traefik
Es wird uns der API-Key ausgegeben. Diesen müssen wir uns unbedingt notieren, da er nur dieses einemal angezeigt wird. Wir kopieren ihn dann in unsere .env-Datei:
nano /opt/containers/crowdsec/.env
TRAEFIK_BOUNCER_KEY=ef422bf99a6883bc9042x0xxx00x0xxx
4.4.3. Traefik erweitern
Nun können wir für jeden Container verdächtige IPs blocken aber wir werden diese Option global Konfigurieren. Damit kann keine unerwünschte IP Adresse auf unsere Services zugreifen.
Um dies zu aktivieren erweitern wir unsere dynamic_conf.yml von Traefik um eine weitere middleware:
nano /opt/containers/traefik/data/dynamic_conf.yml
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
http:
middlewares:
traefikAuth:
basicAuth:
users:
- "benutzer:passworthash"
default:
chain:
middlewares:
- default-security-headers
- gzip
secHeaders:
chain:
middlewares:
- default-security-headers
- gzip
default-security-headers:
headers:
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
frameDeny: true
# Deprecated
# sslRedirect: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
gzip:
compress: {}
crowdsec-bouncer:
forwardauth:
address: http://crowdsec-bouncer-traefik:8080/api/v1/forwardAuth # Hier könnte nun auch bei Bedarf die statische IP 172.31.0.3:8080 verwendet werden
trustForwardHeader: trueCode-Sprache: PHP (php)
Jetzt noch die statische Konfiguration von Traefik anpassen. Wir fügen zu unseren Einstiegspunkten (entryPoints) die gerade definierte Middleware standardgemäß hinzu:
nano /opt/containers/traefik/data/traefik.yml
api:
dashboard: true
certificatesResolvers:
http:
acme:
email: "meine@email.de"
storage: "acme_letsencrypt.json"
httpChallenge:
entryPoint: http
entryPoints:
http:
address: ":80"
http:
redirections:
entryPoint:
to: "https"
scheme: "https"
# An dieser Stelle auskommentiert. Bevor die Anfrage an crowdsec geht wird sie erst an https weitergeleitet
# middlewares:
# - crowdsec-bouncer@file
https:
address: ":443"
http:
middlewares:
- crowdsec-bouncer@file
global:
checknewversion: true
sendanonymoususage: false
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: "proxy"
file:
filename: "./dynamic_conf.yml"
watch: true
providersThrottleDuration: 10
log:
level: "INFO"
filePath: "/var/log/traefik/traefik.log"
accessLog:
filePath: "/var/log/traefik/access.log"
bufferingSize: 100Code-Sprache: CSS (css)
5. Dienste neustarten
Nun starten wir nach der Reihe die Dienste einmal neu. Dannach wird jede eingehende Anfrage von Traefik an den Bouncer weitergeleitet, um zu prüfen, ob die IP auf der Banliste steht. Alle IP Adressen auf der Banliste bekommen dann 403 Forbidden:
docker compose -f /opt/containers/crowdsec/docker-compose.yml up -d --force-recreate
docker compose -f /opt/containers/traefik/docker-compose.yml up -d --force-recreate
Wenn es zu folgendem Fehler kommt:
[+] Running 1/2
⠿ Container crowdsec Started 0.8s
⠿ Container crowdsec-bouncer-traefik Starting 0.5s
Error response from daemon: Address already in useCode-Sprache: JavaScript (javascript)
Dann hat sich Traefik die statische IP Adresse von crowdsec-bouncer-traefik geangelt. Sollte das der Fall sein einfach:
docker compose -f /opt/containers/traefik/docker-compose.yml down
docker compose -f /opt/containers/crowdsec/docker-compose.yml up -d --force-recreate
docker compose -f /opt/containers/traefik/docker-compose.yml up -d --force-recreate
5.1. Erfolgskontrolle
Nun können wir kontrollieren ob CrowdSec Log-Dateien von Traefik gefunden hat und diese auch analysiert:
docker exec crowdsec cscli metrics

6. Crontab einrichten
Die benutzten COLLECTIONS werden überwiegend durch die Community gepflegt und natürlich auch auf neue Crowdsec-Versionen angepasst. Damit wir nicht in einen Fehler laufen oder eine veraltet COLLECTION verwenden ist es Sinnvoll diese regelmäßig zu aktualisieren.
sudo crontab -e
0 * * * * docker exec crowdsec cscli hub update && docker exec crowdsec cscli hub upgrade
7. Authelia verwenden
Anstelle von der htaccess-Authentication kann selbstverständlich auch das noch sicherer Authelia eingesetzt werden. Dafür wurde die folgende Anleitung angepasst:
8. Ältere Anleitungen anpassen
Viele Anleitungen auf GoNeuland sind entstanden bevor es diese hier gab. Das bedeutet wir müssen zumindest kleine Anpassungen an den Traefik Labels des jeweiligen Container machen. So sehen Beispielhaft die typischen Labels einer Anleitung aus:
labels:
- "traefik.enable=true"
- "traefik.http.routers.invidious.entrypoints=http"
- "traefik.http.routers.invidious.rule=Host(`video.euredomain.de`)"
- "traefik.http.middlewares.invidious-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.invidious.middlewares=invidious-https-redirect"
- "traefik.http.routers.invidious-secure.entrypoints=https"
- "traefik.http.routers.invidious-secure.rule=Host(`video.euredomain.de`)"
- "traefik.http.routers.invidious-secure.tls=true"
- "traefik.http.routers.invidious-secure.tls.certresolver=http"
- "traefik.http.routers.invidious-secure.service=invidious"
- "traefik.http.services.invidious.loadbalancer.server.port=3000"
- "traefik.docker.network=proxy"
- "traefik.http.routers.invidious-secure.middlewares=secHeaders@file"Code-Sprache: JavaScript (javascript)
Ich möchte diese jetzt Stück für Stück an die neue Anleitung anpassen euch dabei mitnehmen. Ich zeige euch die Stellen an denen wir was verändern.
Folgender Teil kann entfernt werden, da wir das schon in der traefik.yml definiert haben:
- "traefik.http.middlewares.invidious-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.invidious.middlewares=invidious-https-redirect"Code-Sprache: JavaScript (javascript)
Danke für den Hinweis @Ice-Cue
9. Nützliches
9.1. Remote IP an Container übertragen
Bei diesem Inhalt handelt es sich um exklusiven Content für Community Plus Mitglieder und Supporter.
Bitte logge dich mit deinem Account ein um den Inhalt zu sehen.
Quellen
- https://stage.goneuland.de/traefik-v2-reverse-proxy-fuer-docker-unter-debian-10-einrichten/
- https://docs.ibracorp.io/crowdsec/
- https://www.benjaminrancourt.ca/a-complete-traefik-configuration/
- https://docs.ibracorp.io/crowdsec/crowdsec/docker-compose/traefik-bouncer
- https://blog.vacum.se/securing-mailcow-with-crowdsec/
- https://spad.uk/integrating-crowdsec-with-traefik-discord/
- https://docs.technotim.live/posts/crowdsec-traefik/

Hallo,
danke für die super Anleitung. Soweit funktioniert auch alles. Ich habe nur ein Problem, und das habe ich seit der Installation auf Debian 11 jetzt ein paar Tage beobachtet, dass der Crowd-Sec Container einen Restart alle paar Sekunden macht. So kann ich mich leider auch nicht im Traefik anmelden. Bin für jeden Tipp dankbar!
Seltsam, neuer Server gekauft. Debian 11. Traefik nach Chrisitans Anleitung läuft. Nun crowdsec und ich habe auf meinem frischem System auch beide log nicht.
Fehler/Warnung
crowdsec | time=”10-08-2022 07:55:32″ level=warning msg=”No matching files for pattern /var/log/syslog” type=file
crowdsec | time=”10-08-2022 07:55:32″ level=warning msg=”No matching files for pattern /var/log/crowdsec/traefik/*.log” type=file
Zumindest zeigt er jetzt die access.log von Traefik an. Danke. Im Beispiel in deinem Bild ist da aber noch die traefik.log. Die wird bei mir immer noch nicht angezeigt.
Hallo,
wollte es versuchsweise installieren bekomme aber scheitere schon bei der einrichtung von Traefik. Der Befehl: docker compose -f /opt/containers/traefik/docker-compose.yml up -d wirft die Fehlermeldung: “unknown shorthand flag: ‘f’ in -f” Ein einfaches docker-compose up -d bringt folgenden Fehler: ERROR: Network proxy declared as external but specifies additional attributes (driver, attachable). Bin gerade die Dateien nochmal durchgegangen und dürfte nichts vergessen haben.
Konnte alles nach deiner Anleitung installieren und verwenden. Ich nutze bereits einige Docker-Container und konnte auch ein paar Container umstellen und starten. Aber, Mailcow wollte nicht mit Traefik. Nutzt du Mailcow? Falls ja, wie sehen denn deine Labels aus. Welche Änderungen sind denn durch diese Umstellungen bei den Labels notwendig?
Fehler gefunden: Kopierfehler muss sein:
filenames:
– /var/log/auth.log
– /var/log/syslog
labels:
type: syslog
—
filenames:
– /var/log/crowdsec/traefik/*.log
labels:
type: traefik
—
Inhalt acquis.yaml
filenames:
– /var/log/auth.log
– /var/log/syslog
labels:
type: syslog
filenames:
– /var/log/crowdsec/traefik/*.log
labels:
type: traefik
Weiter geht es in der Installation: Fehler in der acquis ?
crowdsec | time=”08-08-2022 16:50:00″ level=info msg=”loading acquisition file : /etc/crowdsec/acquis.yaml”
crowdsec | time=”08-08-2022 16:50:00″ level=fatal msg=”crowdsec init: Error while loading acquisition config : while loading acquisition configuration: failed to yaml decode /etc/crowdsec/acquis.yaml: yaml: unmarshal errors:\n line 8: key \”filenames\” already set in map\n line 9: field labels already set in type configuration.DataSourceCommonCfg”
—
Vielen Dank psycho0verload, werde ich gleich mal testen. Das wäre ja Klasse.
Volltreffer hiermit geht es: test:$apr1$4hQkHXZs$zwC5Di95PmKfSKaAR/phq0
Ach ja, /etc/containers/traefik/data/traefik.yml muss sein /opt/containers/traefik/data/traefik.yml
3.4. Dashboard mit Passwort schützen
Hier geht es für mich nicht weiter. Traefik läuft, aber ich kann mich nicht mit dem neu angelegten User und dem Kennwort einloggen. Bei Christians Anleitung konnte ich auch keinen eigenen User erstellen. Könntet ihr das bitte mal nachvollziehen? Ich nutze Debian 11.