Wenn mehrere Dienste auf demselben Server über Port 80 (für HTTP) oder 443 (für HTTPS) kommunizieren sollen, kann dies zu Konflikten führen, da normalerweise nur ein Dienst einen bestimmten Port zu einem bestimmten Zeitpunkt belegen kann. Hier kommt Traefik ins Spiel und hilft, dieses Problem zu lösen.
Traefik agiert als Reverse-Proxy und Load-Balancer und ermöglicht es, dass alle eingehenden Anfragen auf Port 80 oder 443 an die richtigen Dienste weitergeleitet werden, basierend auf den von Ihnen konfigurierten Regeln. Dies wird manchmal als “Routing” bezeichnet.
In wie weit unterscheidet sich diese zu der bisherigen vorhandenen Anleitung?
- Meine bisherige Anleitung ist nun schon ein paar Tage alt und ich habe in der Zwischenzeit vieles weiter lernen dürfen.
- Es gab viele wichtige Kommentare, Fragen und Anregungen – vielen Dank dafür!
- Es steht in absehbarer Zeit ein Traefik Major Release an – Version 3
0. Versionierung
Datum | Änderung |
---|---|
04.06.2023 | sleep 30 aus Punkt 5.2. entfernt |
25.05.2023 | Migration ans Ende der Einleitung verschoben |
Initialer Release |
1. Zielsetzung & Vorwort
- Traefik v2 installieren und konfigurieren
- Crowdsec installieren und konfigurieren
- Traefik Services via CrowdSec sichern
- Einzelner Stack
- Wie wir unsere Services mit Traefik verfügbar machen
Hinweis: Bitte beachtet, dass ich nicht jede Änderung im Vergleich zur alten Anleitung ausführlich darlegen werde. Allerdings werde ich besondere Sorgfalt darauf verwenden, an Stellen, an denen die neue Anleitung nicht mehr mit der alten kompatibel ist, einen entsprechenden Hinweis einzufügen. Mein Ziel ist es, euch durch diesen Prozess so reibungslos und verständlich wie möglich zu führen.
Wenn du ein neues Setup, also einen neuen Server aufsetzt, dann kannst du diese Anleitung einfach abarbeiten.
Solltest du aber die alte Anleitung befolgt haben und möchtest nun auf diese FullStack-Anleitung setzten musst du vorher ALLE Container und ALLE Netzwerke außer host,bridge
und none
herunterfahren und dann nach der Anleitung anpassen und Schritt für Schritt wieder hochfahren!
ACHTUNG! Die gesamte Anleitung wurde als root
-User durchgeführt!
2. Voraussetzung
3. Traefik + CrowdSec im Stack vorbereiten
In dieser aktualisierten Anleitung konzentrieren wir uns darauf, Traefik, CrowdSec und alle damit verbundenen Komponenten in einem einzigen Stack zu definieren. Warum? Ganz einfach, die Erfahrung hat gezeigt, dass die Startreihenfolge der Container durchaus relevant sein kann. Mit einem Full-Stack-Ansatz kann ich diesen Aspekt besser steuern und somit eine optimale Performance und Funktionalität gewährleisten.
Wichtiger Hinweis!
Diese Anleitung ist nicht vollständig kompatibel zu meiner alten und wohl bekanntesten Anleitung! Ich werde am Ende ein extra Abschnitt nur der Migration widmen.
3.1. Verzeichnisse / Dateien anlegen
Beginnen wir mit der Erstellung der benötigten Verzeichnisse für den Full-Stack. Im Folgenden wird das Hauptverzeichnis traefik-crowdsec-stack
erstellt, und dann darin Unterordner für traefik
, crowdsec
, config
und zwei zusätzliche Unterordner für config
und data
in crowdsec
.
# Hauptverzeichnis erstellen und zusätzliche Unterordner in 'crowdsec' erstellen mkdir -p /opt/containers/traefik-crowdsec-stack/{traefik,crowdsec/{config,data},config} # Ins Hauptverzeichnis wechseln cd /opt/containers/traefik-crowdsec-stack
Im nächsten Schritt erzeugen wir die notwendigen Dateien und setzen die korrekten Zugriffsrechte.
# .env Datei im Hauptverzeichnis erstellen touch /opt/containers/traefik-crowdsec-stack/.env # Umgebungsspezifische .env Dateien in 'config' erstellen touch /opt/containers/traefik-crowdsec-stack/config/{crowdsec.env,traefik.env,traefik-crowdsec-bouncer.env} # Zusätzliche Dateien in 'traefik' erstellen und Zugriffsrechte für bestimmte Dateien festlegen touch /opt/containers/traefik-crowdsec-stack/traefik/{acme_letsencrypt.json,traefik.yml,dynamic_conf.yml,tls_letsencrypt.json} chmod 600 /opt/containers/traefik-crowdsec-stack/traefik/{acme_letsencrypt.json,tls_letsencrypt.json}
Als nächstes möchten wir sicherstellen, dass alles korrekt angelegt wurde. Hierfür verwenden wir den tree
Befehl. Falls das tree
Programm noch nicht installiert ist, können wir es wie folgt installieren:
Für Ubuntu/Debian:
apt install tree
Jetzt können wir den Befehl tree
Verzeichnis ausführen
tree -L 2 -a /opt/containers/traefik-crowdsec-stack/
um die Struktur zu überprüfen. Die Ausgabe sollte folgendermaßen aussehen:
. ├── config │ ├── crowdsec.env │ ├── traefik.env │ └── traefik-crowdsec-bouncer.env ├── crowdsec │ ├── config │ └── data ├── .env └── traefik ├── acme_letsencrypt.json ├── dynamic_conf.yml ├── tls_letsencrypt.json └── traefik.yml
Wenn eure Ausgabe genau so aussieht, habt ihr alles richtig gemacht und wir können weitermachen. Wenn nicht, überprüft bitte die vorherigen Schritte.
Bevor wir diesen Abschnitt abschließen, sollten wir einige wichtige Unterschiede zu meiner alten Anleitung hervorheben:
- Datenstruktur: Die Art und Weise, wie wir unsere Daten strukturieren, hat sich erheblich verändert. Wir nutzen jetzt eine ordentlichere und effizientere Struktur, die es uns ermöglicht, die Dinge besser zu organisieren und zu verwalten.
- Verwendung von .env Dateien: In dieser Anleitung verwenden wir .env Dateien, um Umgebungsvariablen zu speichern. Dies ist eine übliche Praxis, die uns hilft, sensitive Informationen sicher und organisiert zu halten, und es uns ermöglicht, verschiedene Einstellungen für verschiedene Umgebungen zu haben.
- TLS Resolver: Ein zusätzliches Feature dieser Anleitung ist die Verfügbarkeit eines TLS Resolvers. Dies ist ein mächtiges Werkzeug, das wir im weiteren Verlauf der Anleitung detailliert behandeln werden.
3.2. docker-compose.yml anlegen
Wir beginnen nun mit der Erstellung unserer docker-compose.yml
Datei. Hierfür verwenden wir den Texteditor nano
. Um die Lesbarkeit zu verbessern und die Verwaltung zu erleichtern, teilen wir die Datei in mehrere Abschnitte auf. Jeder Abschnitt befasst sich mit einem bestimmten Aspekt unserer Stack-Konfiguration.
nano docker-compose.yml
Mit dem obigen Befehl öffnen wir nano
und erstellen gleichzeitig die Datei docker-compose.yml
, falls sie noch nicht existiert. Nun können wir mit der Konfiguration unserer Full-Stack-Anwendung beginnen.
# Die Version der Docker Compose-Datei. Hier verwenden wir Version 3.9. version: "3.9" # Der Beginn des 'services' Abschnitts. services:
# Name des Services. crowdsec: # Der Name des Containers, der aus diesem Service erzeugt wird container_name: ${SERVICES_CROWDSEC_CONTAINER_NAME:-crowdsec} # Umgebungsvariablen für den Container. env_file: ./config/crowdsec.env # Hostname des CrowdSec-Containers, kann über eine Umgebungsvariable angepasst werden. hostname: ${SERVICES_CROWDSEC_HOSTNAME:-crowdsec} # Gesundheitsüberprüfung für den CrowdSec-Service healthcheck: test: ["CMD", "cscli", "version"] interval: 20s timeout: 2s retries: 5 start_period: 10s # Docker-Image, das für den Container verwendet wird. image: ${SERVICES_CROWDSEC_IMAGE:-crowdsecurity/crowdsec}:${SERVICES_CROWDSEC_IMAGE_VERSION:-latest} # Netzwerke, zu denen der Container gehört. networks: crowdsec: # Feste IPv4-Adresse vergeben. ipv4_address: ${SERVICES_CROWDSEC_NETWORKS_CROWDSEC_IPV4:-172.31.254.254} # Restart-Strategie für den Container. restart: unless-stopped # Sicherheitsoptionen für den Container. security_opt: - no-new-privileges=true # Volumes, die vom Container verwendet werden. volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - /var/log/auth.log:/var/log/auth.log:ro - /var/log/traefik:/var/log/traefik:ro - ./crowdsec/config:/etc/crowdsec - ./crowdsec/data:/var/lib/crowdsec/data
# Der Name des Service traefik: # Der Name des Containers, der aus diesem Service erzeugt wird container_name: ${SERVICES_TRAEFIK_CONTAINER_NAME:-traefik} # Diese Option sorgt dafür, dass der Traefik-Service erst gestartet wird, # nachdem der Crowdsec-Service healthy ist depends_on: crowdsec: condition: service_healthy # Umgebungsvariablen für den Container. env_file: ./config/traefik.env # Hostname des Traefik-Containers, kann über eine Umgebungsvariable angepasst werden. hostname: ${SERVICES_TRAEFIK_HOSTNAME:-traefik} # Gesundheitsüberprüfung für den Traefik-Service healthcheck: test: ["CMD", "traefik", "healthcheck", "--ping"] interval: 10s timeout: 1s retries: 3 start_period: 10s # Das Docker-Image, das für diesen Service verwendet wird # Version kann über eine Umgebungsvariable angepasst werden. Standard: 2.10 image: ${SERVICES_TRAEFIK_IMAGE:-traefik}:${SERVICES_TRAEFIK_IMAGE_VERSION:-2.10} # Docker Labels für den Traefik-Service. Diese werden für die Traefik-Konfiguration verwendet labels: traefik.docker.network: proxy traefik.enable: "true" traefik.http.routers.traefik.entrypoints: websecure traefik.http.routers.traefik.middlewares: default@file traefik.http.routers.traefik.rule: Host(${SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST}) traefik.http.routers.traefik.service: api@internal traefik.http.routers.traefik.tls: "true" traefik.http.routers.traefik.tls.certresolver: http_resolver traefik.http.services.traefik.loadbalancer.sticky.cookie.httpOnly: "true" traefik.http.services.traefik.loadbalancer.sticky.cookie.secure: "true" traefik.http.routers.pingweb.rule: PathPrefix(`/ping`) traefik.http.routers.pingweb.service: ping@internal traefik.http.routers.pingweb.entrypoints: websecure # Die Netzwerke, zu denen dieser Service gehört networks: crowdsec: # IPv4-Adresse des CrowdSec Containers im Traefik-Netwerk: crowdsec ipv4_address: ${SERVICES_TRAEFIK_NETWORKS_CROWDSEC_IPV4:-172.31.254.253} proxy: # IPv4-Adresse des Traefik Containers im Traefik-Netwerk: proxy ipv4_address: ${SERVICES_TRAEFIK_NETWORKS_PROXY_IPV4:-172.16.255.254} # Die Ports, die diesem Service zugeordnet sind ports: - "80:80" # HTTP - "443:443" # HTTPS # Der Restart-Policy dieses Service restart: unless-stopped # Sicherheitsoptionen für diesen Service security_opt: - no-new-privileges:true # Die Volumes, die diesem Service zugeordnet sind volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - /var/log/traefik/:/var/log/traefik/ - ./traefik/traefik.yml:/traefik.yml:ro - ./traefik/acme_letsencrypt.json:/acme_letsencrypt.json - ./traefik/tls_letsencrypt.json:/tls_letsencrypt.json - ./traefik/dynamic_conf.yml:/dynamic_conf.yml
# Definition des Traefik CrowdSec Bouncer-Dienstes traefik_crowdsec_bouncer: # Der Name des Containers, der aus diesem Service erzeugt wird container_name: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_CONTAINER_NAME:-traefik_crowdsec_bouncer} # Abhängigkeitsdefinition: Dieser Service wird erst gestartet, wenn der Crowdsec-Service als "healthy" gekennzeichnet ist depends_on: crowdsec: condition: service_healthy # Pfad zur .env-Datei für den Traefik CrowdSec Bouncer-Dienst env_file: ./config/traefik-crowdsec-bouncer.env # Der Hostname des Containers, kann über eine Umgebungsvariable angepasst werden hostname: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_HOSTNAME:-traefik-crowdsec-bouncer} # Docker-Image, das für den Container verwendet wird. Die Version kann über eine Umgebungsvariable angepasst werden image: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_IMAGE:-fbonalair/traefik-crowdsec-bouncer}:${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_IMAGE_VERSION:-latest} # Netzwerke, zu denen der Container gehört networks: crowdsec: # Feste IPv4-Adresse für den Container in diesem Netzwerk ipv4_address: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_NETWORKS_CROWDSEC_IPV4:-172.31.254.252} # Restart-Strategie für den Container. 'unless-stopped' bedeutet, dass der Container immer neu gestartet wird, es sei denn, er wird manuell gestoppt restart: unless-stopped
# Definition der Netzwerke, die von den Services verwendet werden networks: # Definition des 'proxy' Netzwerks proxy: # Der Name des Netzwerks, kann über eine Umgebungsvariable angepasst werden name: ${NETWORKS_PROXY_NAME:-proxy} # Der Treiber, der für das Netzwerk verwendet wird, hier ist es 'bridge' driver: bridge # IP-Adress-Management-Konfiguration (IPAM) ipam: # Konfiguration des IP-Adress-Subnetzes für das Netzwerk config: - subnet: ${NETWORKS_PROXY_SUBNET_IPV4:-172.30.0.0/16} # Wenn 'attachable' auf 'true' gesetzt ist, können Standalone-Container an dieses Netzwerk angehängt werden attachable: true # Definition des 'crowdsec' Netzwerks crowdsec: # Der Name des Netzwerks, kann über eine Umgebungsvariable angepasst werden name: ${NETWORKS_CROWDSEC_NAME:-crowdsec} # Der Treiber, der für das Netzwerk verwendet wird, hier ist es 'bridge' driver: bridge # IP-Adress-Management-Konfiguration (IPAM) ipam: # Konfiguration des IP-Adress-Subnetzes für das Netzwerk config: - subnet: ${NETWORKS_CROWDSEC_SUBNET_IPV4:-172.31.0.0/16} # Wenn 'attachable' auf 'true' gesetzt ist, können Standalone-Container an dieses Netzwerk angehängt werden attachable: true
version: "3.9" services: crowdsec: container_name: ${SERVICES_CROWDSEC_CONTAINER_NAME:-crowdsec} env_file: ./config/crowdsec.env hostname: ${SERVICES_CROWDSEC_HOSTNAME:-crowdsec} healthcheck: test: ["CMD", "cscli", "version"] interval: 20s timeout: 2s retries: 5 start_period: 10s image: ${SERVICES_CROWDSEC_IMAGE:-crowdsecurity/crowdsec}:${SERVICES_CROWDSEC_IMAGE_VERSION:-latest} networks: crowdsec: ipv4_address: ${SERVICES_CROWDSEC_NETWORKS_CROWDSEC_IPV4:-172.31.254.254} restart: unless-stopped security_opt: - no-new-privileges=true volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - /var/log/auth.log:/var/log/auth.log:ro - /var/log/traefik:/var/log/traefik:ro - ./crowdsec/config:/etc/crowdsec - ./crowdsec/data:/var/lib/crowdsec/data traefik: container_name: ${SERVICES_TRAEFIK_CONTAINER_NAME:-traefik} depends_on: crowdsec: condition: service_healthy env_file: ./config/traefik.env hostname: ${SERVICES_TRAEFIK_HOSTNAME:-traefik} healthcheck: test: ["CMD", "traefik", "healthcheck", "--ping"] interval: 10s timeout: 1s retries: 3 start_period: 10s image: ${SERVICES_TRAEFIK_IMAGE:-traefik}:${SERVICES_TRAEFIK_IMAGE_VERSION:-2.10} labels: traefik.docker.network: proxy traefik.enable: "true" traefik.http.routers.traefik.entrypoints: websecure traefik.http.routers.traefik.middlewares: default@file traefik.http.routers.traefik.rule: Host(${SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST}) traefik.http.routers.traefik.service: api@internal traefik.http.routers.traefik.tls: "true" traefik.http.routers.traefik.tls.certresolver: http_resolver traefik.http.services.traefik.loadbalancer.sticky.cookie.httpOnly: "true" traefik.http.services.traefik.loadbalancer.sticky.cookie.secure: "true" traefik.http.routers.pingweb.rule: PathPrefix(`/ping`) traefik.http.routers.pingweb.service: ping@internal traefik.http.routers.pingweb.entrypoints: websecure networks: crowdsec: ipv4_address: ${SERVICES_TRAEFIK_NETWORKS_CROWDSEC_IPV4:-172.31.254.253} proxy: ipv4_address: ${SERVICES_TRAEFIK_NETWORKS_PROXY_IPV4:-172.30.255.254} ports: - "80:80" - "443:443" restart: unless-stopped security_opt: - no-new-privileges:true volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - /var/log/traefik/:/var/log/traefik/ - ./traefik/traefik.yml:/traefik.yml:ro - ./traefik/acme_letsencrypt.json:/acme_letsencrypt.json - ./traefik/tls_letsencrypt.json:/tls_letsencrypt.json - ./traefik/dynamic_conf.yml:/dynamic_conf.yml traefik_crowdsec_bouncer: container_name: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_CONTAINER_NAME:-traefik_crowdsec_bouncer} depends_on: crowdsec: condition: service_healthy env_file: ./config/traefik-crowdsec-bouncer.env hostname: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_HOSTNAME:-traefik-crowdsec-bouncer} image: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_IMAGE:-fbonalair/traefik-crowdsec-bouncer}:${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_IMAGE_VERSION:-latest} networks: crowdsec: ipv4_address: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_NETWORKS_CROWDSEC_IPV4:-172.31.254.252} restart: unless-stopped networks: proxy: name: ${NETWORKS_PROXY_NAME:-proxy} driver: bridge ipam: config: - subnet: ${NETWORKS_PROXY_SUBNET_IPV4:-172.30.0.0/16} attachable: true crowdsec: name: ${NETWORKS_CROWDSEC_NAME:-crowdsec} driver: bridge ipam: config: - subnet: ${NETWORKS_CROWDSEC_SUBNET_IPV4:-172.31.0.0/16} attachable: true
Es ist zu beachten, dass wir nun keine direkten Änderungen an der docker-compose.yml
Datei mehr vornehmen müssen. Die meisten Einstellungen, einschließlich der Container-Namen, Hostnamen, Netzwerkeinstellungen und verwendeten Docker-Images, werden im nächsten Schritt über Umgebungsvariablen in einer .env
Datei definiert.
3.3. DOTENV Konfiguration
In diesem Schritt bearbeiten wir die .env
Datei, um die Dienste und Netzwerkeinstellungen anzupassen.
nano /opt/containers/traefik-crowdsec-stack/.env
Hier ist unser Setup:
# Service Crowdsec SERVICES_CROWDSEC_CONTAINER_NAME=crowdsec SERVICES_CROWDSEC_HOSTNAME=crowdsec SERVICES_CROWDSEC_IMAGE=crowdsecurity/crowdsec SERVICES_CROWDSEC_IMAGE_VERSION=latest SERVICES_CROWDSEC_NETWORKS_CROWDSEC_IPV4=172.31.254.254 # Service Traefik SERVICES_TRAEFIK_CONTAINER_NAME=traefik SERVICES_TRAEFIK_HOSTNAME=traefik SERVICES_TRAEFIK_IMAGE=traefik SERVICES_TRAEFIK_IMAGE_VERSION=2.10 SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST=`traefik.DeineDomainHier.de` SERVICES_TRAEFIK_NETWORKS_CROWDSEC_IPV4=172.31.254.253 SERVICES_TRAEFIK_NETWORKS_PROXY_IPV4=172.30.255.254 # Service Traefik Crowdsec Bouncer SERVICES_TRAEFIK_CROWDSEC_BOUNCER_CONTAINER_NAME=traefik_crowdsec_bouncer SERVICES_TRAEFIK_CROWDSEC_BOUNCER_HOSTNAME=traefik-crowdsec-bouncer SERVICES_TRAEFIK_CROWDSEC_BOUNCER_IMAGE=fbonalair/traefik-crowdsec-bouncer SERVICES_TRAEFIK_CROWDSEC_BOUNCER_IMAGE_VERSION=latest SERVICES_TRAEFIK_CROWDSEC_BOUNCER_NETWORKS_CROWDSEC_IPV4=172.31.254.252 # Netzwerkeinstellungen NETWORKS_PROXY_NAME=proxy NETWORKS_PROXY_SUBNET_IPV4=172.30.0.0/16 NETWORKS_CROWDSEC_NAME=crowdsec NETWORKS_CROWDSEC_SUBNET_IPV4=172.31.0.0/16
Bis auf eine Ausnahme ist dieses Beispielsetup bereits optimiert und erfordert keine weiteren Anpassungen, um richtig zu funktionieren. Die einzige Zeile, die du anpassen musst, ist SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST
. Hier definierst du die eigene Domain für das Traefik-Dashboard. Denke daran, `traefik.DeineDomainHier.de`
durch die tatsächliche Domain zu ersetzen, welche auch via A oder CNAME auf den richtigen Server zeigt, die du für das Traefik-Dashboard verwenden möchtest.
Achtung! Die ``
sind unabdingbar! Hier könnten aber auch mehrere Domains definiert werden:
SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST=`traefik.DeineDomainHier.de`,`www.traefik.DeineDomainHier.de`
3.4. Erläuterung zur Konfiguration
3.4.1. Healthchecks
Unsere Konfiguration nutzt Healthchecks für Traefik und CrowdSec. Healthchecks sind praktische Funktionen, die uns ermöglichen zu überprüfen, ob ein Service ordnungsgemäß läuft. Wenn ein Healthcheck fehlschlägt, weiß Docker, dass mit diesem Service etwas nicht stimmt, und kann entsprechend reagieren.
Die Healthchecks sind in diesem Kontext besonders wichtig, weil wir mit ihnen und der depends_on
-Funktion die Reihenfolge und Abhängigkeiten der einzelnen Services in unserem Stack besser kontrollieren können.
Die depends_on
-Option erlaubt es uns, die Startreihenfolge unserer Container festzulegen. Ein Container, der von einem anderen Container abhängt, wird erst gestartet, wenn der abhängige Container vollständig hochgefahren und betriebsbereit ist. Mit Healthchecks können wir sicherstellen, dass ein Service nicht nur gestartet wurde, sondern tatsächlich ordnungsgemäß funktioniert, bevor wir einen abhängigen Service starten.
In unserem Fall sorgt dies dafür, dass der Traefik und CrowdSec vollständig betriebsbereit sind, bevor der Traefik CrowdSec Bouncer gestartet wird, was uns dabei hilft, sicherzustellen, dass unser Stack stabil und zuverlässig läuft.
3.4.2. Netzwerkkonfiguration
In unserer Konfiguration vergeben wir für die beiden Netzwerke proxy
und crowdsec
spezifische IP-Adressbereiche. Zudem weisen wir den drei Services jeweils feste IP-Adressen zu, die sich am Ende des jeweils verfügbaren IP-Bereichs befinden. Aber warum machen wir das eigentlich?
Der IP-Adressbereich jedes Netzwerks wird festgelegt, um eine gewisse Konsistenz in unserer Setup-Konfiguration zu gewährleisten. Wir weisen jeder Service-Instanz im jeweiligen Netzwerk eine spezifische IP-Adresse zu, die sich am Ende des verfügbaren IP-Bereichs befindet. Dadurch stellen wir sicher, dass die IP-Adressen der Services konstant bleiben und es unwahrscheinlich ist, dass sie versehentlich von Docker’s DHCP-Dienst einem anderen Container zugewiesen werden. Dies könnte zu Adresskonflikten führen.
Zudem benötigen viele Systeme, wie zum Beispiel WordPress, die als Docker-Container laufen, die genaue IP-Adresse des Proxy-Servers (in unserem Fall Traefik). Sollte diese IP-Adresse nicht festgelegt sein, können Fehlfunktionen auftreten. Das liegt daran, dass sich die IP-Adresse bei einem neuen DHCP-Lease ändern könnte, was dazu führen würde, dass die Einstellungen von WordPress oder ähnlichen Systemen nicht mehr korrekt wären.
Durch die Festlegung von spezifischen IP-Adressbereichen und die Zuweisung von IP-Adressen am Ende dieser Bereiche an unsere Services sorgen wir für eine stabile und konsistente Netzwerkkonfiguration. Dies ermöglicht es uns, später weitere Container sicher hinzuzufügen, die dann vom Docker-Netzwerk-DHCP eine Adresse aus dem Anfangsbereich des Netzwerks zugewiesen bekommen können.
3.4.3. Neustart und Abhängigkeiten
Unsere Verwendung eines Docker Stacks bietet weitere Vorteile in Bezug auf die Wartung und Zuverlässigkeit unseres Systems. Innerhalb eines Docker Stacks werden alle definierten Netzwerke und Dienste als zusammenhängende Einheit behandelt. Das bedeutet, dass bei einem Neustart des Stacks alle Dienste in der korrekten Reihenfolge und mit den notwendigen Abhängigkeiten hochgefahren werden.
Durch diese Organisation wird sichergestellt, dass, falls das System neu gestartet werden muss oder aus irgendeinem Grund ausfällt, alle Dienste und Netzwerke ordnungsgemäß und in der korrekten Reihenfolge wieder hergestellt werden.
Das trägt nicht nur zu einem stabileren System bei, sondern erleichtert auch die Wartung, da wir nicht manuell jeden Dienst in einer bestimmten Reihenfolge starten müssen. Der Docker Stack kümmert sich automatisch darum, was letztlich Zeit spart und das Risiko von Fehlern reduziert.
4. Traefik-Konfiguration
4.1. Konfiguration der traefik.yml
Jetzt widmen wir uns der Konfigurationsdatei traefik.yml
. In dieser Datei setzen wir statische Konfigurationsoptionen fest.
nano /opt/containers/traefik-crowdsec-stack/traefik/traefik.yml
Hier ein unsere Konfiguration:
api: dashboard: true metrics: prometheus: addrouterslabels: true certificatesResolvers: http_resolver: acme: email: "deine@email.de" storage: "acme_letsencrypt.json" httpChallenge: entryPoint: web tls_resolver: acme: tlsChallenge: true email: "deine@email.de" storage: "tls_letsencrypt.json" entryPoints: ping: address: ":88" web: address: ":80" http: redirections: entryPoint: to: "websecure" scheme: "https" middlewares: - traefik-crowdsec-bouncer@file websecure: address: ":443" http: middlewares: - traefik-crowdsec-bouncer@file proxyProtocol: trustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 forwardedHeaders: trustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 ping: entryPoint: "ping" global: checknewversion: true sendanonymoususage: false experimental: hub: true plugins: real-ip: moduleName: github.com/Paxxs/traefik-get-real-ip version: "v1.0.2" 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: 100
Beachte bitte, dass du die E-Mail-Adressen unter certificatesResolvers
zwei mal anpasst. Sie dienen als Kontaktinformationen für Let’s Encrypt und sollten daher auf eine gültige E-Mail-Adresse gesetzt sein, die du kontrollierst.
Hinweis! An dieser Stelle darf nur eine E-Mail-Adresse gesetzt werden. Zwei unterschiedliche führen zu einem Fehler:
traefik.go:81: command traefik error: unable to initialize certificates resolver "tls_resolver", all the acme resolvers must use the same email
4.2. Konfiguration der dynamic_conf.yml
Jetzt widmen wir uns der Konfigurationsdatei dynamic_conf.yml
. In dieser Datei setzen wir statische Konfigurationsoptionen fest.
nano /opt/containers/traefik-crowdsec-stack/traefik/dynamic_conf.yml
Hier ein unsere Konfiguration:
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: default: chain: middlewares: - default-security-headers - gzip default-security-headers: headers: browserXssFilter: true contentTypeNosniff: true forceSTSHeader: true frameDeny: true stsIncludeSubdomains: true stsPreload: true stsSeconds: 31536000 customFrameOptionsValue: "SAMEORIGIN" gzip: compress: {} traefik-crowdsec-bouncer: forwardauth: address: http://traefik-crowdsec-bouncer:8080/api/v1/forwardAuth trustForwardHeader: true real-ip-cf: plugin: real-ip: Proxy: - proxyHeadername: "*" realIP: Cf-Connecting-Ip OverwriteXFF: true
4.3. Erläuterung zu Traefik-Konfiguration
4.3.1. Änderung im ACME-Bereich
Unter dem Abschnitt certificatesResolvers
haben wir den Bezeichner für den HTTP-Resolver von http
in http_resolver
geändert.
certificatesResolvers: http_resolver: acme: email: "deine@email.de" storage: "acme_letsencrypt.json" httpChallenge: entryPoint: web
Der Grund für diese Änderung ist, die Klarheit und Verständlichkeit der Konfigurationsdatei zu verbessern. Da der Begriff http
an mehreren Stellen in der traefik.yml
Konfiguration verwendet wird, kann dies zu Verwirrung führen. Durch die Umbenennung in http_resolver
verdeutlichen wir, dass es sich hier speziell um den Mechanismus zur Erstellung des Zertifikats handelt, nicht um den allgemeinen HTTP-Eintrag unter entryPoints
. Dies trägt zur Verbesserung der Lesbarkeit und des Verständnisses der Konfiguration bei.
4.3.2. Hinzufügen des tls_resolver
Unter dem Abschnitt certificatesResolvers
haben wir nun auch einen TLS-Resolver: tls_resolver
tls_resolver: acme: tlsChallenge: true email: "deine@email.de" storage: "tls_letsencrypt.json"
Die TLS-Challenge (oder TLS-ALPN-01 Challenge) ist eine moderne und effektive Methode zur Überprüfung der Domainkontrolle für die Ausstellung von Let’s Encrypt-Zertifikaten. Sie nutzt eine spezielle TLS-Erweiterung namens “Application-Layer Protocol Negotiation” (ALPN) zur Kommunikation mit dem Let’s Encrypt-Validierungsserver während des TLS-Handshakes.
Für die Entwicklung von Python-Webanwendungen, insbesondere solchen, die auf dem Flask-Framework basieren, kann die Verwendung eines TLS-Resolvers besonders vorteilhaft sein. Viele solcher Anwendungen laufen auf Port 443 und profitieren daher von der Verwendung der TLS-Challenge zur Zertifikatserzeugung.
Wichtig zu beachten ist, dass die Verwendung der TLS-Challenge spezifische Anforderungen an die Server- und Netzwerkkonfiguration stellt. Unter anderem muss Ihr Server den ALPN-Erweiterungsstandard unterstützen und Port 443 muss in Ihrer Firewall offen sein. Daher ist es empfehlenswert, die Eignung Ihrer Server- und Netzwerkkonfiguration zu überprüfen, bevor Sie sich für die Verwendung der TLS-Challenge entscheiden.
4.3.3. Überarbeitung der EntryPoints
In unserem aktualisierten Setup haben wir einige Anpassungen an den entryPoints vorgenommen. Insbesondere haben wir den Namen des http
entryPoint zu web
und den https
entryPoint zu websecure
geändert.
entryPoints: ping: address: ":88" web: address: ":80" http: redirections: entryPoint: to: "websecure" scheme: "https" middlewares: - traefik-crowdsec-bouncer@file websecure: address: ":443" http: middlewares: - traefik-crowdsec-bouncer@file proxyProtocol: trustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 forwardedHeaders: trustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16
Diese Änderungen sind hauptsächlich aus Kompatibilitäts- und Klarheitsgründen durchgeführt worden. Die offizielle Dokumentation von Traefik verwendet in der Regel web
und websecure
als entryPoint-Namen, und durch die Einhaltung dieser Benennungskonvention werden unsere Konfigurationen leichter verständlich für jeden, der mit Traefik vertraut ist. Darüber hinaus erleichtert die Einhaltung der offiziellen Benennungskonventionen das Verständnis und die Anwendung der offiziellen Traefik-Dokumentation.
Es ist wichtig zu beachten, dass trotz der Namensänderungen die Funktionalität der entryPoints gleich bleibt – web
leitet den unverschlüsselten HTTP-Verkehr auf Port 80 und websecure
handhabt den verschlüsselten HTTPS-Verkehr auf Port 443.
4.3.4. Anpassung der Middleware-Namen
In der neuesten Version der Konfiguration haben wir die Middleware für beide Einträge web
und websecure
aktualisiert. Die Middleware wurde von crowdsec-bouncer@file
auf traefik-crowdsec-bouncer@file
geändert.
entryPoints: ... web: ... http: middlewares: - traefik-crowdsec-bouncer@file websecure: ... http: middlewares: - traefik-crowdsec-bouncer@file
Der Grund für diese Änderung liegt in der klaren Namensführung und Übersichtlichkeit. Der Name traefik-crowdsec-bouncer
verdeutlicht, dass dieser Bouncer speziell für Traefik konzipiert ist. Dies ist besonders wichtig, da es verschiedene Bouncer für unterschiedliche Anwendungen und Kontexte gibt. Ein klares und explizites Benennen erleichtert das Verständnis und die Wartung des Setups.
5. CrowdSec-Konfiguration
5.1. Konfiguration der crowdsec.env
Zur Konfiguration von CrowdSec bearbeiten wir die Datei config/crowdsec.env
. Diese Datei ist essentiell, um die Umgebungsvariablen übersichtlich und zentral zu definieren. Durch die Auslagerung dieser Definitionen in eine separate Datei, bleibt unser Setup klar strukturiert und wartungsfreundlich.
nano /opt/containers/traefik-crowdsec-stack/config/crowdsec.env
Dort definieren wir ein paar Environments welche wir in CrowdSec benötigen:
PGID="1000" COLLECTIONS="crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/whitelist-good-actors crowdsecurity/postfix crowdsecurity/dovecot crowdsecurity/nginx"
PGID
: Dies steht für “Group ID” und bestimmt, unter welcher Gruppen-ID der CrowdSec-Prozess ausgeführt wird. Im vorliegenden Fall ist das die Gruppen-ID “1000”. Die Gruppen-ID sollte der ID einer existierenden Gruppe in deinem System entsprechen, die die benötigten Zugriffsrechte hat.COLLECTIONS
: Dies ist eine Liste von sogenannten “Collection”-Namen. Eine Collection in CrowdSec ist eine Gruppe von Szenarien, Parsern und Post-Overflows, die einen bestimmten Zweck erfüllen. Im vorliegenden Fall werden die folgenden Collections verwendet:crowdsecurity/traefik
: Diese Collection ist speziell für die Überwachung und den Schutz von Traefik, einem modernen Reverse-Proxy und Load-Balancer.crowdsecurity/http-cve
: Diese Collection enthält Szenarien zur Erkennung von bekannten Schwachstellen und Angriffen (CVEs) auf HTTP-Server.crowdsecurity/whitelist-good-actors
: Eine Collection, die dafür sorgt, dass bekannte “gute” Akteure nicht fälschlicherweise als bösartig erkannt werden.crowdsecurity/postfix
undcrowdsecurity/dovecot
: Diese beiden Collections sind speziell für die Überwachung und den Schutz von Postfix- und Dovecot-Mailservern.crowdsecurity/nginx
: Eine Collection, die speziell für die Überwachung und den Schutz von Nginx-Webservern entwickelt wurde.
Diese Umgebungsvariablen sind entscheidend für die Konfiguration von CrowdSec. Sie ermöglichen es, das Verhalten von CrowdSec fein abzustimmen und an die spezifischen Anforderungen deines Systems anzupassen. Es ist wichtig, diese Werte sorgfältig zu überprüfen und zu aktualisieren, um die bestmögliche Sicherheit zu gewährleisten.
5.2. Konfiguration der acquis.yaml
Zu diesem Zeitpunkt könntest du bemerkt haben, dass wir bisher keine acquis.yaml
-Datei angelegt haben. Der Grund dafür ist, dass diese Datei Teil der Ressourcen ist, die das Docker-Image von CrowdSec bereitstellt. Um die Konfigurationsdateien von CrowdSec zu generieren, müssen wir den CrowdSec-Dienst kurz starten. Dazu wechseln wir zunächst in das Verzeichnis unserer Docker-Compose-Datei für den Traefik-CrowdSec-Stack und starten dann den Dienst:
cd /opt/containers/traefik-crowdsec-stack docker compose up crowdsec -d && docker compose down
Mit dem Befehl docker compose up crowdsec -d
starten wir den CrowdSec-Dienst im Hintergrundmodus. Schließlich beenden wir den Dienst wieder mit docker compose down
.
Jetzt sollten alle Konfigurationsdateien von CrowdSec vorhanden sein und wir können nun die acquis.yaml
-Datei nach anpassen. In der acquis.yaml
-Datei werden die Log-Dateien definiert welche eingelesen und beobachtet werden sollen. Hier ist es wichtig, dass die Logdateien und Services auch in CrowdSec eingebunden sind. Dies habe ich in dieser Anleitung bereits in der docker-compose.yml
angelegt:
version: "3.9" services: crowdsec: ... volumes: ... # Hier wird die auth.log vom System in CrowdSec eingebracht - /var/log/auth.log:/var/log/auth.log:ro # Hier wird die der Ordner in den Traefik seine Logs schreibt in CrowdSec eingebracht - /var/log/traefik:/var/log/traefik:ro ... traefik: ... volumes: ... # Hier wird der Ordner in den Traefik seine Logs schreibt auf den Host gemounted - /var/log/traefik/:/var/log/traefik/ ... ... ...
Nun zur acquis.yaml
-Datei. Die haben wir nun generiert. Nach aktuellem Stand sieht diese so aus:
filenames: - /var/log/nginx/*.log - ./tests/nginx/nginx.log #this is not a syslog log, indicate which kind of logs it is labels: type: nginx --- filenames: - /var/log/auth.log - /var/log/syslog labels: type: syslog --- filename: /var/log/apache2/*.log labels: type: apache2
Wir passen diese nun an unsere Bedürfnisse an und dafür öffnen wir sie mit nano
.
nano /opt/containers/traefik-crowdsec-stack/crowdsec/config/acquis.yaml
Dort fügen wir folgendes ein bzw. ersetzen den vorhandenen Inhalt:
filenames: - /var/log/auth.log - /var/log/syslog labels: type: syslog --- filenames: - /var/log/traefik/*.log labels: type: traefik ---
In ersten Abschnitt der Konfigurationsdatei werden die auth.log
und syslog
Dateien zur Analyse hinzugefügt. Das Label “syslog” wird diesen Dateien zugeordnet. Dies ermöglicht es CrowdSec, bestimmte Analysemethoden auf diese Dateien anzuwenden, die für syslog-Logs geeignet sind.
Im zweiten Abschnitt der Konfigurationsdatei fügen wir alle Logdateien hinzu, die im Verzeichnis /var/log/traefik/
liegen und deren Dateinamen mit .log
enden. Diesen Dateien weisen wir das Label “traefik” zu. So kann CrowdSec spezifische Analysemethoden anwenden, die für Traefik-Logs geeignet sind.
6. Traefik und Crowdsec verheiraten – der Bouncer
CrowdSec hat nun die Fähigkeit, Logdateien zu analysieren und verdächtige IP-Adressen in eine Sperrliste aufzunehmen – das ist ein großer Schritt! Doch in der aktuellen Konfiguration haben wir noch keine Maßnahmen ergriffen, um potenzielle Angriffe tatsächlich abzuwehren. Das ist die Aufgabe sogenannter “Bouncer” in CrowdSec.
Es gibt eine Vielzahl an verschiedenen Bouncern für diverse Einsatzgebiete: Es gibt zum Beispiel Bouncer für Firewalls wie iptables oder nftables, und es gibt auch Bouncer zur Steuerung der Firewall von Cloudflare. Für unseren konkreten Anwendungsfall ist jedoch der Traefik Bouncer besonders interessant, da er die Fähigkeit hat, speziell mit unserem Traefik Load Balancer zu interagieren.
6.1. Traefik CrowdSec Bouncer
Wie du vielleicht bemerkt hast, haben wir in der zu Beginn definierten Docker-Compose-Datei bereits alle notwendigen Komponenten für den Traefik CrowdSec Bouncer unter dem Abschnitt services -> traefik_crowdsec_bouncer
eingefügt.
An dieser Stelle brauchen wir nur noch die zugehörige .env-Datei, die wir zuvor erstellt haben, um zwei weitere Werte zu erweitern in dem wir die Datei mit nano
öffnen:
nano /opt/containers/traefik-crowdsec-stack/config/traefik-crowdsec-bouncer.env
Jetzt fügen wir folgende Variablen ein:
# Access-Token damit Bouncer und CrowdSec kommunizieren können CROWDSEC_BOUNCER_API_KEY= # Hostname mit richtigem Port von CrowdSec CROWDSEC_AGENT_HOST=${SERVICES_CROWDSEC_HOSTNAME}:8080
6.1.1. Access Token anlegen
In der traefik-crowdsec-bouncer.env
haben wir die Variable CROWDSEC_BOUNCER_API_KEY
angelegt und um diese mit einem Access-Token bzw. API-Key auch nutzen zu können müssen wir diesen wie folgt generieren:
cd /opt/containers/traefik-crowdsec-stack docker compose up crowdsec -d docker compose exec -t crowdsec cscli bouncers add traefik-crowdsec-bouncer docker compose down
So, oder so ähnlich sollte die Ausgabe aussehen:
[+] Running 3/3 ✔ Network crowdsec Created 0.1s ✔ Network proxy Created 0.1s ✔ Container crowdsec Started 0.4s Api key for 'traefik-crowdsec-bouncer': ee21c448d67e04550dec5b07b42ad6ee Please keep this key since you will not be able to retrieve it! [+] Running 3/3 ✔ Container crowdsec Removed 10.2s ✔ Network crowdsec Removed 0.2s ✔ Network proxy Removed
Nun speichern wir uns den generierten Schlüssel (in diesem Beispiel: ee21c448d67e04550dec5b07b42ad6ee
) in die Zwischenablage und fügen via nano
in unsere config/traefik-crowdsec-bouncer.env
.
# Access-Token damit Bouncer und CrowdSec kommunizieren können CROWDSEC_BOUNCER_API_KEY=ee21c448d67e04550dec5b07b42ad6ee # Hostname mit richtigem Port von CrowdSec CROWDSEC_AGENT_HOST=${SERVICES_CROWDSEC_HOSTNAME}:8080
6.1.2. Traefik kontrollieren
Wie wir bereits in einem früheren Abschnitt dieser Anleitung festgelegt haben, wird in der dynamic_conf.yml
-Datei die traefik-crowdsec-bouncer
-Konfiguration definiert:
traefik-crowdsec-bouncer: forwardauth: address: http://traefik-crowdsec-bouncer:8080/api/v1/forwardAuth trustForwardHeader: true
Dieser Abschnitt ermöglicht es Traefik, mit dem CrowdSec Bouncer zu kommunizieren. Hierbei müssen wir sicherstellen, dass der unter address
angegebene Hostname dem entspricht, den wir in der .env-Datei unter folgendem Punkt definiert haben:
SERVICES_TRAEFIK_CROWDSEC_BOUNCER_HOSTNAME=traefik-crowdsec-bouncer
Leider ist es in dieser Konfiguration nicht ohne Weiteres möglich, die Variable direkt zu setzen. Alternativ kann hier jedoch auch die IP-Adresse, die unter:
SERVICES_TRAEFIK_CROWDSEC_BOUNCER_NETWORKS_CROWDSEC_IPV4=172.31.254.252
definiert ist, verwendet werden.
In der traefik.yml
-Datei haben wir unter entryPoints
Traefik angewiesen, bei jeder Anfrage, die über den jeweiligen Point web
bzw. websecure
kommt, diese direkt über die Middleware an den Bouncer zu senden:
entryPoints: web: address: ":80" http: redirections: entryPoint: to: "websecure" scheme: "https" middlewares: - traefik-crowdsec-bouncer@file websecure: address: ":443" http: middlewares: - traefik-crowdsec-bouncer@file
Diese Konfiguration gewährleistet letztendlich das erfolgreiche Zusammenspiel zwischen allen Komponenten. Traefik kommuniziert mit dem Bouncer, der wiederum mit CrowdSec kommuniziert. Diese strukturierte Kommunikation zwischen den Komponenten sorgt dafür, dass potenziell schädliche Anfragen effektiv blockiert werden.
7. Dienst starten
Uff! Das war wirklich eine lange und gründliche Anleitung bis jetzt. Ich habe mein Bestes gegeben, um viele Aspekte direkt zu erläutern und das Verständnis der Funktionsweise sowie des Aufbaus des Stacks zu erleichtern.
Jetzt, bevor wir mit dem Starten des Dienstes fortfahren, möchte ich dich bitten: Nimm dir einen Moment Zeit, geh nochmal alle Schritte durch und prüfe, ob alle Dateien richtig erstellt und mit dem passenden Inhalt gefüllt wurden.
Also, gönn dir eine kleine Pause, streck dich mal und gönn deinen Augen eine kurze Verschnaufpause vom Bildschirm. Dann, mit frischem Blick und voller Energie, können wir uns dem nächsten Schritt zuwenden. Und keine Sorge, wir sind schon fast am Ziel!
☕️☕️☕️
Bereit?
cd /opt/containers/traefik-crowdsec-stack docker compose up -d
🚀🚀🚀 Fertig, oder?
So, wir sind fast durch, aber es gibt noch ein paar Dinge, die wir erledigen müssen. Was fehlt? Die Überprüfung und die bereits angekündigte Migration der alten Anleitung zu diesem Setup.
Außerdem werde ich noch einige optionale Dinge hinzufügen. Es handelt sich dabei um Extras, die nicht unbedingt notwendig sind, aber je nach deinen spezifischen Anforderungen nützlich sein könnten. Bleib also dran und lass uns diese letzten Schritte gemeinsam erledigen!
8. Überprüfung
Natürlich sollten wir zwischendurch und gemäß dieser Anleitung immer wieder überprüfen, ob alles funktioniert, wie es sollte. Das tun wir jetzt nach all diesen Schritten.
Wir haben den Container ja bereits gestartet. Als erstes überprüfen wir, ob alle Container als “healthy” (gesund) markiert sind:
cd /opt/containers/traefik-crowdsec-stack docker compose ps
root@mail:/opt/containers/traefik-crowdsec-stack# docker compose ps NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS crowdsec crowdsecurity/crowdsec:latest "/bin/sh -c '/bin/ba…" crowdsec 3 days ago Up 19 hours (healthy) traefik traefik:2.10 "/entrypoint.sh trae…" traefik 3 days ago Up 22 hours (healthy) 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp traefik_crowdsec_bouncer fbonalair/traefik-crowdsec-bouncer:latest "/app" traefik_crowdsec_bouncer 3 days ago Up 3 days (healthy) root@mail:/opt/containers/traefik-crowdsec-stack#
Wenn wir alles richtig gemacht haben, sind alle Container als “healthy” markiert.
Dann rufen wir das Traefik-Dashboard mit der zuvor festgelegten URL auf. Das Dashboard sollte sich öffnen und auch ein valides LE-Zertifikat haben.
Beim Öffnen des Dashboards werden auch Logdateien erstellt, und diese überprüfen wir als nächstes:
cd /var/log/traefik ls -all cat traefik.log cat access.log
Hier sollten wir idealerweise die Dateien traefik.log
und access.log
finden, und in beide sollte etwas geschrieben sein. Wenn die Datei access.log nicht vorhanden ist, ist das kein Beinbruch, sollte aber beobachtet werden.
Wenn das alles passt, betrachten wir mit dem Befehl:
docker exec crowdsec cscli metrics
die ganz oben stehenden Acquisition Metrics
. Dort sollte nun die traefik.log
aufgeführt sein. Wenn die Datei access.log
im System vorhanden ist, sollte sie ebenfalls dort erscheinen.
Sollte etwas nicht funktionieren schaue als erstes “Hinweis zu Kommentaren” an ☕️
9. Optional
Es gibt noch einige optionale Punkte. Diesen Bereich werde ich nach und nach erweitern bzw. auf vorhandene Anleitungen verweisen!
9.1. CrowdSec aktuell halten
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. Dazu legen wir uns einen Cronjob an:
crontab -e
Dieser Cronjob wird jeden Tag um 03:00 Uhr aufgerufen, aktualisiert die Pakete aus dem CrowdSec Hub und läd die Konfiguration neu.
0 3 * * * docker exec crowdsec cscli hub update && docker exec crowdsec cscli hub upgrade && docker exec -t crowdsec kill -SIGHUP 1 >/dev/null 2>&1
9.2. Traefik Dashboard schützen
Um das Traefik Dashboard abzusichern und unbefugten Zugriff zu verhindern, wird empfohlen, eine zusätzliche Authentifizierung einzurichten. Dadurch wird eine Benutzername-Passwort-Überprüfung erforderlich, um auf das Dashboard zugreifen zu können.
Traefik bietet eine einfache Methode zur Implementierung der Authentifizierung. Um dies zu erreichen, müssen wir zunächst die folgenden Pakete auf unserem System installieren:
apt update && apt install apache2-utils
Nachdem wir diese Schritte durchgeführt haben, müssen wir innerhalb von Traefik eine Middleware konfigurieren. Bevor wir dies tun, erstellen wir ein Passwort mit dem folgenden Befehl:
echo $(htpasswd -nb DeinUsername 'DeinSuperSicheresPasswort') # Ausgabe DeinUsername:$apr1$xSRxT4UY$wk42WRgVzBW5Pf69sS5aT.
Es wird empfohlen, die Ausgabe zu speichern, zum Beispiel durch Kopieren und Einfügen in eine Textdatei.
9.2.1. dynamic_conf.yml anpassen
Jetzt ist es an der Zeit, die Middleware zu konfigurieren. Dazu öffnen wir die Datei dynamic_conf.yml mit Texteditor:
nano /opt/containers/traefik-crowdsec-stack/traefik/dynamic_conf.yml
Wir befinden uns im Abschnitt “http” -> “middlewares”. Bisher sieht dieser Teil folgendermaßen aus:
... http: middlewares: default: chain: middlewares: - default-security-headers - gzip default-security-headers: headers: browserXssFilter: true contentTypeNosniff: true forceSTSHeader: true frameDeny: true stsIncludeSubdomains: true stsPreload: true stsSeconds: 31536000 customFrameOptionsValue: "SAMEORIGIN" gzip: compress: {} traefik-crowdsec-bouncer: forwardauth: address: http://traefik-crowdsec-bouncer:8080/api/v1/forwardAuth trustForwardHeader: true real-ip-cf: plugin: real-ip: Proxy: - proxyHeadername: "*" realIP: Cf-Connecting-Ip OverwriteXFF: true ...
Nun fügen wir die Konfiguration für unsere Schutzmaßnahmen hinzu:
traefikAuth: basicAuth: users: - "DeinUsername:$apr1$xSRxT4UY$wk42WRgVzBW5Pf69sS5aT."
Hierbei ersetzen wir natürlich “DeinUsername” und “$apr1$xSRxT4UY$wk42WRgVzBW5Pf69sS5aT.” durch die zuvor generierten Werte.
Dieses Snippet fügen wir an beliebiger Stelle in die middlewares ein:
... http: middlewares: default: chain: middlewares: - default-security-headers - gzip default-security-headers: headers: browserXssFilter: true contentTypeNosniff: true forceSTSHeader: true frameDeny: true stsIncludeSubdomains: true stsPreload: true stsSeconds: 31536000 customFrameOptionsValue: "SAMEORIGIN" gzip: compress: {} traefik-crowdsec-bouncer: forwardauth: address: http://traefik-crowdsec-bouncer:8080/api/v1/forwardAuth trustForwardHeader: true real-ip-cf: plugin: real-ip: Proxy: - proxyHeadername: "*" realIP: Cf-Connecting-Ip OverwriteXFF: true traefikAuth: basicAuth: users: - "DeinUsername:$apr1$xSRxT4UY$wk42WRgVzBW5Pf69sS5aT." ...
9.2.2. docker-compose.yml anpassen
Im letzten Schritt müssen wir Anpassungen in der Datei docker-compose.yml vornehmen. Öffnen Sie die Datei mit einem Texteditor:
nano /opt/containers/traefik-crowdsec-stack/docker-compose.yml
Suchen Sie den Abschnitt für Traefik:
traefik: container_name: ${SERVICES_TRAEFIK_CONTAINER_NAME:-traefik} depends_on: crowdsec: condition: service_healthy env_file: ./config/traefik.env hostname: ${SERVICES_TRAEFIK_HOSTNAME:-traefik} healthcheck: test: ["CMD", "traefik", "healthcheck", "--ping"] interval: 10s timeout: 1s retries: 3 start_period: 10s image: ${SERVICES_TRAEFIK_IMAGE:-traefik}:${SERVICES_TRAEFIK_IMAGE_VERSION:-2.10} labels: traefik.docker.network: proxy traefik.enable: "true" traefik.http.routers.traefik.entrypoints: websecure traefik.http.routers.traefik.middlewares: default@file traefik.http.routers.traefik.rule: Host(${SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST}) traefik.http.routers.traefik.service: api@internal traefik.http.routers.traefik.tls: "true" traefik.http.routers.traefik.tls.certresolver: http_resolver traefik.http.services.traefik.loadbalancer.sticky.cookie.httpOnly: "true" traefik.http.services.traefik.loadbalancer.sticky.cookie.secure: "true" traefik.http.routers.pingweb.rule: PathPrefix(`/ping`) traefik.http.routers.pingweb.service: ping@internal traefik.http.routers.pingweb.entrypoints: websecure networks: crowdsec: ipv4_address: ${SERVICES_TRAEFIK_NETWORKS_CROWDSEC_IPV4:-172.31.254.253} proxy: ipv4_address: ${SERVICES_TRAEFIK_NETWORKS_PROXY_IPV4:-172.16.255.254} ports: - "80:80" - "443:443" restart: unless-stopped security_opt: - no-new-privileges:true volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - /var/log/traefik/:/var/log/traefik/ - ./traefik/traefik.yml:/traefik.yml:ro - ./traefik/acme_letsencrypt.json:/acme_letsencrypt.json - ./traefik/tls_letsencrypt.json:/tls_letsencrypt.json - ./traefik/dynamic_conf.yml:/dynamic_conf.yml
Innerhalb dieses Abschnitts finden Sie unter “labels” das Label:
traefik.http.routers.traefik.middlewares: default@file
Erweitern Sie diese Zeile nun um unsere gerade erstellte Middleware “traefikAuth”:
traefik.http.routers.traefik.middlewares: default@file,traefikAuth@file
9.2.3 Neustart des Setups
Abschließend führen wir einen Neustart des FullStacks durch und überprüfen anschließend, ob beim Aufruf des Traefik Dashboards nun ein Passwort abgefragt wird.
Wechseln Sie zum Verzeichnis des Traefik-Crowdsec-Stacks:
cd /opt/containers/traefik-crowdsec-stack
Starten Sie den FullStack neu und erzwingen Sie die Neuerstellung der Container:
docker compose up -d --force-recreate
Nachdem der Neustart abgeschlossen ist, überprüfen Sie, ob beim Aufruf des Traefik Dashboards nun ein Passwort abgefragt wird.
9.3. Erweiterung der Firewall (IP-Tables bzw. UFW) mit CrowdSec
Jetzt wollen wir CrowdSec auf unserem System installieren und die Firewall mithilfe des Bouncers um CrowdSec erweitern. In dieser Anleitung haben wir CrowdSec bereits über Docker in unser System integriert. Doch wir möchten den Firewall-Bouncer direkt auf unserem System installieren und ihn dann mit CrowdSec verknüpfen, das in einem Docker-Container läuft.
9.3.1. Repository für CrowdSec Firewall Bouncer
Um den Firewall Bouncer zu installieren, müssen wir das entsprechende Repository auf unserem System einbinden. Wir führen den folgenden Befehl aus, um die erforderlichen Repositorys hinzuzufügen:
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash
Dadurch werden die benötigten Repositorys zu unserem System hinzugefügt.
9.3.2. Installation des Firewall Bouncers
Die Pakete für den CrowdSec Firewall Bouncer sind in unseren Repositories verfügbar. Wir müssen das Paket entsprechend unserem Firewall-System auswählen: IPTables bzw. UFW
Verwenden wir den folgenden Befehl, um den CrowdSec Firewall Bouncer für IPTables bzw. UFW zu installieren:
apt install crowdsec-firewall-bouncer-iptables
9.3.3. Access Token anlegen
Ähnlich wie in Schritt 6.1.1. benötigen wir auch für den CrowdSec Firewall Bouncer für IPTables einen Access Token, um mit CrowdSec kommunizieren zu können. Um diesen Access Token zu erhalten, führen wir die folgenden Schritte aus:
cd /opt/containers/traefik-crowdsec-stack docker compose exec -t crowdsec cscli bouncers add crowdsec-firewall-bouncer-iptables
So könnte die erwartete Ausgabe aussehen:
API-Schlüssel für 'crowdsec-firewall-bouncer-iptables': ee21c448d67e04550dec5b07b42ad6ee Wir müssen beachten, dass wir diesen Schlüssel gut aufbewahren, da wir ihn nicht erneut abrufen können!
Nun speichern wir uns den generierten Schlüssel (in diesem Beispiel: ee21c448d67e04550dec5b07b42ad6ee
) in die Zwischenablage.
9.3.4. Anpassung der Konfiguration
Um die Konfiguration anzupassen, geben wir einfach den folgenden Befehl ein:
nano /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml
Vorher:
api_url: http://127.0.0.1:8080/ api_key:
Nachher:
api_url: http://172.31.254.254:8080/ api_key: ee21c448d67e04550dec5b07b42ad6ee
Hierbei ersetzen wir die Werte für “api_url” und “api_key” entsprechend. Beachtet, dass die euer eigener Access-Token individuell ist und von den oben gezeigten Beispielen abweichen wird.
9.3.5. CrowdSec Firewall Bouncer starten
Jetzt starten wir den Bouncer mit dem folgenden Befehl:
systemctl start crowdsec-firewall-bouncer
Anschließend überprüfen wir den Status mit dem Befehl:
systemctl status crowdsec-firewall-bouncer
Die Ausgabe sollte in etwa wie folgt aussehen:
crowdsec-firewall-bouncer.service - The firewall bouncer for CrowdSec Loaded: loaded (/etc/systemd/system/crowdsec-firewall-bouncer.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2022-10-24 23:51:09 CEST; 21s ago Process: 14877 ExecStartPre=/usr/sbin/crowdsec-firewall-bouncer -c /etc/crowdsec/bouncers/crowd .. ..
Dadurch stellen wir sicher, dass der CrowdSec Firewall Bouncer ordnungsgemäß gestartet ist.
9.3.6. Anzeigen der CrowdSec Bouncer-Liste
Jetzt können wir uns alle CrowdSec Bouncer anzeigen lassen, um sicherzustellen, dass unser Firewall Bouncer dort aufgeführt wird.
Führen wir den folgenden Befehl aus:
docker exec crowdsec cscli bouncers list
Das Ergebnis sollte in etwa wie folgt aussehen:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Name IP Address Valid Last API pull Type Version Auth Type ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- traefik-crowdsec-bouncer 172.31.255.252 ✔️ 2023-05-24T21:14:45Z Go-http-client 1.1 api-key crowdsec-firewall-bouncer-iptables 172.31.240.1 ✔️ 2023-05-24T21:15:27Z crowdsec-firewall-bouncer v0.0.27-debian-pragmatic-8d09f19d69e92a63e63888794af3a57c6a- api-key de3489 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Wir müssen beachten, dass die im obigen Beispiel aufgeführten IP-Adressen individuell für unser Setup sind und bei uns andere Werte haben werden.
Damit haben wir bestätigt, dass alles erfolgreich funktioniert hat und unser Firewall Bouncer in der Liste aufgeführt wird.
9.3.7. Auslesen des CrowdSec Firewall Bouncer Logs
Nun werfen wir einen Blick auf das Log des Firewall Bouncers. Dies kann besonders im Fehlerfall sehr hilfreich sein. Geben wir dazu den folgenden Befehl ein:
cat /var/log/crowdsec-firewall-bouncer.log
In den letzten Zeilen sollten wir Informationen sehen, dass unser Bouncer neue Entscheidungen von CrowdSec erhalten hat. Ein Beispiel könnte wie folgt aussehen:
time="24-10-2022 23:51:09" level=info msg="Using API key auth" time="24-10-2022 23:51:09" level=info msg="Processing new and deleted decisions . . ." time="24-10-2022 23:51:09" level=info msg="14 decisions added" time="24-10-2022 23:52:59" level=info msg="1 decision added" time="24-10-2022 23:54:29" level=info msg="1 decision added"
Wir müssen beachten, dass die genauen Informationen in unserem Log individuell sein können und von den oben gezeigten Beispielen abweichen können. Durch das Auslesen des Logs können wir jedoch überprüfen, ob unser Bouncer neue Entscheidungen von CrowdSec erhalten hat.
9.3.8. Automatisches Starten des CrowdSec Firewall Bouncers
Um sicherzustellen, dass unser Firewall Bouncer automatisch bei jedem Serverneustart gestartet wird, können wir einen Cron-Eintrag erstellen. Dadurch ersparen wir uns das manuelle Starten nach jedem Neustart. Credits an @ice-cue für diesen Tipp in der alten Anleitung!
Geben wir den folgenden Befehl ein, um den Cron-Editor zu öffnen:
crontab -e
Dort fügen wir nun folgende Zeile hinzu:
@reboot sleep 120 && systemctl start crowdsec-firewall-bouncer
Mit diesem Befehl wird der CrowdSec Firewall Bouncer 120 Sekunden nach dem Serverneustart gestartet. Dadurch ist gewährleistet, dass unser Firewall Bouncer automatisch beim Start des Servers gestartet wird.
9.3.9. Anzeigen der gebannten IP-Adressen
Wir könnn uns mit einem Befehl alle aktuellen Bans anschauen:
docker exec crowdsec cscli decisions list
9.3.10. Eigene IP-Adresse bannen
Um zu testen, ob alles funktioniert, wollen wir uns selbst bannen. Dadurch haben wir für EINE MINUTE keinen Zugriff mehr auf unseren Server. Zuerst ermitteln wir unsere eigene IP-Adresse mithilfe einer Webseite wie z. B. https://www.wieistmeineip.de/.
Anschließend geben wir den folgenden Befehl ein. Achtet darauf, dass ihr die “1.2.3.4” durch eure eigene IP-Adresse ersetzt:
docker exec crowdsec cscli decisions add --ip 1.2.3.4 --duration 1m
Wenn wir alles richtig gemacht haben, sollten unsere SSH-Verbindung sowie alle anderen Verbindungen zu unserem Server nun eine Minute lang blockiert bzw. gesperrt sein.
Bitte beachtet, dass dies nur zu Testzwecken empfohlen ist und wir sicherstellen sollten, dass wir wieder Zugriff auf unseren Server erhaltet, nachdem der Test abgeschlossen ist.
9.4. Logrotate für Traefik
Es ist bereits bekannt, dass die traefik.log
-Datei sehr schnell wächst, insbesondere wenn das Debug-Level auf “info” gesetzt ist. Das kann schnell zu Speicherplatzproblemen führen, wenn sie nicht gehandhabt wird. Traefik selbst bietet keine eingebaute Log-Rotation-Funktion, aber zum Glück gibt es eine Standardkomponente namens Logrotate in vielen Linux-Distributionen wie Ubuntu, die uns dabei helfen kann.
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.
10. Migration
Ich bin mir ziemlich sicher, dass dieser Beitrag meinen alten Beitrag ersetzen wird. Genau so ist es auch gedacht. Mein Plan ist, den alten Beitrag weiterhin zu erhalten, allerdings mit dem Hinweis, dass es diesen neuen gibt. Weder Christian, ich noch irgendeiner der Co-Autoren wird in der Lage sein, alle Anleitungen zeitnah anzupassen. Deshalb möchte ich hier eine allgemeine Migrationsanleitung beschreiben.
- Für diejenigen, die ihre bisherige Konfiguration bereits individuell verändert haben, gehe ich davon aus, dass sie den Stack gut genug verstanden haben, um ihr Setup selbst zu übertragen.
- Für diejenigen, die einfach nur dankbar sind, dass das alte Setup funktioniert hat, gibt es hier die Migrationsanleitung.
10.1. Neuen Container hinzufügen
Um einen neuen Container über Traefik verfügbar zu machen und gleichzeitig durch CrowdSec zu schützen, müssen wir in der zugehörigen Docker-compose.yml die Ports entfernen und dem entsprechenden Container Labels hinzufügen. Hier ein Beispiel mit WordPress:
Dies ist die docker-compose.yml aus der WordPress-Dokumentation auf hub.docker.com:
version: '3.1' services: wordpress: image: wordpress restart: always ports: - 8080:80 environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: exampleuser WORDPRESS_DB_PASSWORD: examplepass WORDPRESS_DB_NAME: exampledb volumes: - wordpress:/var/www/html db: image: mysql:5.7 restart: always environment: MYSQL_DATABASE: exampledb MYSQL_USER: exampleuser MYSQL_PASSWORD: examplepass MYSQL_RANDOM_ROOT_PASSWORD: '1' volumes: - db:/var/lib/mysql volumes: wordpress: db:
Dies wird dann zu folgender Konfiguration geändert:
version: '3.1' services: wordpress: environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_NAME: exampledb WORDPRESS_DB_PASSWORD: examplepass WORDPRESS_DB_USER: exampleuser image: wordpress labels: traefik.docker.network: proxy traefik.enable: "true" traefik.http.routers.wordpress-secure.entrypoints: websecure traefik.http.routers.wordpress-secure.middlewares: default@file traefik.http.routers.wordpress-secure.rule: Host(`meinwordpress.de`) traefik.http.routers.wordpress-secure.service: wordpress traefik.http.routers.wordpress-secure.tls: "true" traefik.http.routers.wordpress-secure.tls.certresolver: http_resolver traefik.http.routers.wordpress.entrypoints: web traefik.http.routers.wordpress.rule: Host(`meinwordpress.de`) traefik.http.services.wordpress.loadbalancer.server.port: "80" networks: default: null proxy: null restart: always volumes: - wordpress:/var/www/html db: environment: MYSQL_DATABASE: exampledb MYSQL_PASSWORD: examplepass MYSQL_RANDOM_ROOT_PASSWORD: "1" MYSQL_USER: exampleuser image: mysql:5.7 networks: default: null restart: always volumes: - db:/var/lib/mysql networks: default: proxy: external: true volumes: db: wordpress:
Eine kurze Erklärung dazu: Die Ports müssen nicht mehr explizit freigegeben (exposed) werden, da dies nun Traefik übernimmt. Wir teilen Traefik lediglich über Labels mit, welcher Resolver verwendet werden soll und über welchen Port Traefik auf WordPress zugreifen kann. Zusätzlich muss dem WordPress-Container noch das Traefik-Netzwerk namens “proxy” zugewiesen werden. Allerdings sollte dies nur dem WordPress-Container zugewiesen werden, da wir zwar die Datenbank gemeinsam mit WordPress im “default”-Netzwerk betreiben, die Datenbank jedoch nicht öffentlich zugänglich machen möchten.
10.2. Beispiel Mailcow anpassen
Eine sehr bekannte Anleitung hier im Blog ist die “Mailcow – E-Mail Komplettsytem mit Antivirus, Spam Filer, Webmail, Webfrontend installieren mittels Docker und Traefik” die von Christian und mir gepflegt wird. In der Anleitung von Mailcow ist an Punkt “4.2 docker-compose.override.yml erstellen“ der Teil an dem die Labels definiert werden.
10.2.1. Ursprüngliche Konfiguration
version: '3.9' services: nginx-mailcow: labels: - "traefik.enable=true" - "traefik.http.routers.nginx-mailcow.entrypoints=http" - "traefik.http.routers.nginx-mailcow.rule=HostRegexp(`{host:(autodiscover|autoconfig|mail|mta-sts|imap|pop3|smtp).+}`)" - "traefik.http.routers.nginx-mailcow-secure.entrypoints=https" - "traefik.http.routers.nginx-mailcow-secure.rule=Host(`mail.euredomain.de`)" - "traefik.http.routers.nginx-mailcow-secure.rule=HostRegexp(`{host:(autodiscover|autoconfig|mail|mta-sts|imap|pop3|smtp).+}`)" - "traefik.http.routers.nginx-mailcow-secure.rule=Host(`mail.euredomain.de`, `autodiscover.euredomain.de`, `autoconfig.euredomain.de`, `mta-sts.euredomain.de`)" - "traefik.http.routers.nginx-mailcow-secure.middlewares=default@file" - "traefik.http.routers.nginx-mailcow-secure.tls=true" - "traefik.http.routers.nginx-mailcow-secure.tls.certresolver=http" - "traefik.http.routers.nginx-mailcow-secure.service=nginx-mailcow" - "traefik.http.services.nginx-mailcow.loadbalancer.server.port=80" - "traefik.docker.network=proxy" networks: - proxy certdumper: image: humenius/traefik-certs-dumper:latest restart: unless-stopped network_mode: none command: --restart-containers mailcowdockerized-postfix-mailcow-1,mailcowdockerized-dovecot-mailcow-1 volumes: - /opt/containers/traefik/data:/traefik:ro - /var/run/docker.sock:/var/run/docker.sock:ro - ./data/assets/ssl:/output:rw environment: DOMAIN: ${MAILCOW_HOSTNAME} ACME_FILE_PATH: "/traefik/acme_letsencrypt.json" networks: proxy: external: true
10.2.2. Neue Konfiguration
version: '3.9' services: nginx-mailcow: labels: - "traefik.enable=true" - "traefik.http.routers.nginx-mailcow.entrypoints=web" - "traefik.http.routers.nginx-mailcow.rule=HostRegexp(`{host:(autodiscover|autoconfig|mail|mta-sts|imap|pop3|smtp).+}`)" - "traefik.http.routers.nginx-mailcow-secure.entrypoints=websecure" - "traefik.http.routers.nginx-mailcow-secure.rule=Host(`mail.euredomain.de`)" - "traefik.http.routers.nginx-mailcow-secure.rule=HostRegexp(`{host:(autodiscover|autoconfig|mail|mta-sts|imap|pop3|smtp).+}`)" - "traefik.http.routers.nginx-mailcow-secure.rule=Host(`mail.euredomain.de`, `autodiscover.euredomain.de`, `autoconfig.euredomain.de`, `mta-sts.euredomain.de`)" - "traefik.http.routers.nginx-mailcow-secure.middlewares=default@file" - "traefik.http.routers.nginx-mailcow-secure.tls=true" - "traefik.http.routers.nginx-mailcow-secure.tls.certresolver=http_resolver" - "traefik.http.routers.nginx-mailcow-secure.service=nginx-mailcow" - "traefik.http.services.nginx-mailcow.loadbalancer.server.port=80" - "traefik.docker.network=proxy" networks: - proxy certdumper: image: humenius/traefik-certs-dumper:latest restart: unless-stopped network_mode: none command: --restart-containers mailcowdockerized-postfix-mailcow-1,mailcowdockerized-dovecot-mailcow-1 volumes: - /opt/containers/traefik-crowdsec-stack/traefik:/traefik:ro - /var/run/docker.sock:/var/run/docker.sock:ro - ./data/assets/ssl:/output:rw environment: DOMAIN: ${MAILCOW_HOSTNAME} ACME_FILE_PATH: "/traefik/acme_letsencrypt.json" networks: proxy: external: true
10.2.3. Änderungen
- Änderung der Eintrittspunkte:
- Von: “traefik.http.routers.nginx-mailcow.entrypoints=http”
- Zu: “traefik.http.routers.nginx-mailcow.entrypoints=web”
- Von: “traefik.http.routers.nginx-mailcow-secure.entrypoints=https”
- Zu: “traefik.http.routers.nginx-mailcow-secure.entrypoints=websecure”
- Änderung des Zertifikat-Resolver:
- Von: “traefik.http.routers.nginx-mailcow-secure.tls.certresolver=http”
- Zu: “traefik.http.routers.nginx-mailcow-secure.tls.certresolver=http_resolver”
- Änderung des Volumes für den “certdumper” Dienst:
- Von: “/opt/containers/traefik/data:/traefik:ro”
- Zu: “/opt/containers/traefik-crowdsec-stack/traefik:/traefik:ro”
10.2.4. Konfiguration mit neuerer Notationen
Mit den steigenden Docker Versionen hat auch eine leicht angepasste Notation Einzug genommen, welche ich zumindest kurz zeigen möchte:
version: '3.9' services: nginx-mailcow: labels: traefik.enable: true traefik.http.routers.nginx-mailcow.entrypoints: web traefik.http.routers.nginx-mailcow.rule: HostRegexp(`{host:(autodiscover|autoconfig|mail|mta-sts|imap|pop3|smtp).+}`) traefik.http.routers.nginx-mailcow-secure.entrypoints: websecure traefik.http.routers.nginx-mailcow-secure.rule: Host(`mail.euredomain.de`) traefik.http.routers.nginx-mailcow-secure.rule: HostRegexp(`{host:(autodiscover|autoconfig|mail|mta-sts|imap|pop3|smtp).+}`) traefik.http.routers.nginx-mailcow-secure.rule: Host(`mail.euredomain.de`, `autodiscover.euredomain.de`, `autoconfig.euredomain.de`, `mta-sts.euredomain.de`) traefik.http.routers.nginx-mailcow-secure.middlewares: default@file traefik.http.routers.nginx-mailcow-secure.tls: true traefik.http.routers.nginx-mailcow-secure.tls.certresolver: http_resolver traefik.http.routers.nginx-mailcow-secure.service: nginx-mailcow traefik.http.services.nginx-mailcow.loadbalancer.server.port: "80" traefik.docker.network: proxy networks: - proxy certdumper: image: humenius/traefik-certs-dumper:latest restart: unless-stopped network_mode: none command: --restart-containers mailcowdockerized-postfix-mailcow-1,mailcowdockerized-dovecot-mailcow-1 volumes: - /opt/containers/traefik-crowdsec-stack/traefik:/traefik:ro - /var/run/docker.sock:/var/run/docker.sock:ro - ./data/assets/ssl:/output:rw environment: DOMAIN: ${MAILCOW_HOSTNAME} ACME_FILE_PATH: "/traefik/acme_letsencrypt.json" networks: proxy: external: true
10.3. Beispiel Nextcloud Server
Eine weitere sehr bekannte Anleitung hier im Blog ist die “Nextcloud Server – mit Docker Compose und Traefik installieren” die von Christian gepflegt wird. In der Anleitung von Nextcloud ist an Punkt “2. Docker Compose anlegen“ der Teil an dem die Labels definiert werden.
10.3.1. Alte Konfiguration
version: '3.3' services: ... nextcloud-app: environment: TRUSTED_PROXIES: 172.18.0.2/16 ... labels: - "traefik.enable=true" - "traefik.http.routers.nextcloud.entrypoints=https" - "traefik.http.routers.nextcloud.rule=(Host(`nextcloud.euredomain.de`))" - "traefik.http.routers.nextcloud.tls=true" - "traefik.http.routers.nextcloud.tls.certresolver=http" - "traefik.http.routers.nextcloud.service=nextcloud" - "traefik.http.services.nextcloud.loadbalancer.server.port=80" - "traefik.docker.network=proxy" - "traefik.http.routers.nextcloud.middlewares=nextcloud-dav,default@file" - "traefik.http.middlewares.nextcloud-dav.replacepathregex.regex=^/.well-known/ca(l|rd)dav" - "traefik.http.middlewares.nextcloud-dav.replacepathregex.replacement=/remote.php/dav/" ...
10.3.2. Neue Notation und Konfiguration
version: '3.3' services: ... nextcloud-app: environment: TRUSTED_PROXIES: 172.16.255.254 ... labels: traefik.docker.network: proxy traefik.enable: "true" traefik.http.middlewares.nextcloud-dav.replacepathregex.regex: ^/.well-known/ca(l|rd)dav traefik.http.middlewares.nextcloud-dav.replacepathregex.replacement: /remote.php/dav/ traefik.http.routers.nextcloud.entrypoints: websecure traefik.http.routers.nextcloud.middlewares: nextcloud-dav,default@file traefik.http.routers.nextcloud.rule: (Host(`nextcloud.euredomain.de`)) traefik.http.routers.nextcloud.service: nextcloud traefik.http.routers.nextcloud.tls: "true" traefik.http.routers.nextcloud.tls.certresolver: http_resolver traefik.http.services.nextcloud.loadbalancer.server.port: "80" ...
10.3.3. Hinweis zur Nextcloud Anleitung
An dieser Stelle ist nochmal ein gesonderter Hinweis zur Anleitung angebracht! Der Punkt “2.1 Trusted Proxy IP ermitteln” entfällt vollständig! In dem FullStack hat Traefik immer eine fest definierte IPv4-Adresse. So müssen wir keine Range mehr an Nextcloud weitergeben sondern können uns auf die spezifische Adresse von Traefik im proxy
-Netzwerk verlassen!
10.4. Liste bereits migrierter Anleitungen
Hier ist eine Liste von Anleitungen, die bereits erfolgreich migriert wurden:
Diese Anleitungen wurden sorgfältig überarbeitet und sind nun auf die neue Umgebung und die aktuelle Anleitung angepasst.
Hinweis
Hinweis zu Traefik v3.0beta2
Das in diesem Artikel beschriebene Setup ist grundsätzlich auch mit Traefik v3.0beta2 kompatibel. Ich habe es erfolgreich getestet. Es ist jedoch wichtig zu beachten, dass in der aktuellen Beta-Version ein bekannter Fehler vorhanden ist, der dazu führt, dass das Dashboard trotz korrekter Konfiguration nicht erreichbar ist. Wie kann ich dann sicher sein, dass das Setup korrekt funktioniert? Zum Beispiel funktioniert die oben beschriebene WordPress-Anleitung perfekt und ist mit Traefik v3.0beta2 gut erreichbar. Daher ist es sicher zu schlussfolgern, dass das Setup korrekt funktioniert, trotz des Bugs mit dem Dashboard.
Hinweis zu Kommentaren
Wenn etwas nicht funktioniert, gehe noch einmal alle einzelnen Punkte in der Anleitung durch. Ich habe die Anleitung mehrfach getestet und Christian hat sie auch durchgesehen. Wenn du sicher bist, dass du alles richtig konfiguriert hast und das noch einmal überprüft hast, dann hinterlasse gerne einen Kommentar. Der Blog wird von Christian betrieben und er, sowie alle Co-Autoren, bemühen uns, alle Fragen und Probleme zu lösen – allerdings ist dies auch immer von unserer verfügbaren Zeit abhängig!
Bitte abonniert GoNeuland, damit dieser Blog uns auch weiterhin viele Jahre Freude bereiten kann 😉
Hi, danke für die gute Bearbeitung in den letzen Tagen.
Ich hätte hier eine kleine Ergänzung für Personen, die den Cloudflare-Proxy zusäztlich nutzen möchten. Hierfür ist einfach in der traefik.yml (Traefik Konfiguration) folgendes zu ergänzen:
…
entryPoints:
ping:
address: “:88”
web:
address: “:80”
http:
redirections:
entryPoint:
to: “websecure”
scheme: “https”
middlewares:
– traefik-crowdsec-bouncer@file
websecure:
address: “:443”
http:
middlewares:
– traefik-crowdsec-bouncer@file
proxyProtocol:
trustedIPs:
– 10.0.0.0/8
– 172.16.0.0/12
– 192.168.0.0/16
forwardedHeaders:
trustedIPs:
– 10.0.0.0/8
– 172.16.0.0/12
– 192.168.0.0/16
– 103.21.244.0/22
– 103.22.200.0/22
– 103.31.4.0/22
– 104.16.0.0/13
– 104.24.0.0/14
– 108.162.192.0/18
– 131.0.72.0/22
– 141.101.64.0/18
– 162.158.0.0/15
– 172.64.0.0/13
– 173.245.48.0/20
– 188.114.96.0/20
– 190.93.240.0/20
– 197.234.240.0/22
– 198.41.128.0/17
– 2400:cb00::/32
– 2606:4700::/32
– 2803:f800::/32
– 2405:b500::/32
– 2405:8100::/32
– 2a06:98c0::/29
– 2c0f:f248::/32
…
Es handelt sich hierbei um die offiziellen Cloudflare-Proxy-IPs, die man für die Weiterleitungsheader akzeptieren muss. Nachdem diese eingetragen sind, einfach die orangene Wolke anschalten und man nutzt nun erfolgreich den Cloudflare Proxy für alle HTTPS Anfragen.
Mir ist außerdem aufgefallen, dass die traefik.env gar nicht benutzt wird. Ist dies absicht?
Lieben Dank nochmal für eure Gute Arbeit und viele Grüße
Yowa
Hi, danke für die Anleitung. Ich erhalte kein ACME-Zertifikat, weil mein Domainname zu lang ist (habe leider keinen Einfluss).
Gibt es eine Möglichkeit, in Eurem Setup dies über eine Subject Alternate Name (SAN) in den Griff zu bekommen?
Danke, Donludovico
Anbei noch die Fehlermeldung:
Unable to obtain ACME certificate for domains “traefik.507e48d4-2960-4155-917b-e2f8421217a3.ul.bw-cloud-instance.org”:
unable to generate a certificate for the domains [traefik.507e48d4-2960-4155-917b-e2f8421217a3.ul.bw-cloud-instanc
e.org]:
acme: error: 400 :: POST :: https://acme-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier ::
NewOrder request did not include a SAN short enough to fit in CN” routerName=traefik@docker rule=”Host(
traefik.507e48d4-2960-4155-917b-e2f8</span>
)” providerName=http_resolver.acme ACME CA=”https://acme-v02.api.letsencrypt.org/directory”<span class="ql-font-monospace">421217a3.ul.bw-cloud-instance.org
Ich habe gerade versucht auf einem anderen Server all das genau nochmal durchzuführen, aber bei “7. Dienst starten” kommt es zu folgendem Problem:
Error response from daemon: driver failed programming external connectivity on endpoint traefik (“Nummer+Zahlen”): Error starting userland proxy: listen tcp4 0.0.0.0:443: bind: address already in use
Der Server auf dem ich das ebenso installieren wollte hat diesmal Plex, wenn das wichtig ist bezüglich Fehlermeldung.
Anscheinend wird Port 443 verwendet und Traefik Container kann nicht gestartet werden.
lsof -i :443
zeigt mir folgende Prozess an:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 401 root 6u IPv4 4859056730 0t0 TCP server.mydomain.xx:https (LISTEN)
nginx 403 nginx 6u IPv4 4175398569 0t0 TCP server.mydomain.xx:https (LISTEN)
Kann mir einer helfen?
Edit: Hab Server neu aufgesetzt ohne Plesk. Bevor Plesk mich in den Wahnsinn treibt.
Komme gerade aus einem Kurzurlaub wieder und habe auf der Hinfahrt schon diese neue Anleitung gefunden. Mein erster Gedanke war, das war es wohl mit meinem Server. Ich habe dann mal die Anleitung an meinem kleinen Proxmox Server probiert. Ich hatte nicht viel Zeit und habe einfach nur den Code kopiert und den Rest nicht gelesen. Und was soll ich sagen! Es hat alles geklappt. Keine Fehler! Top Anleitung. Nun kommt der Sommerurlaub und im Juli stelle ich dann meinen Hauptserver inkl. Mailcow etc um. Vielen Dank für die tolle Anleitung und Arbeit. Ich habe damals gleich die Qualität der Anleitungen hier erkannt und sofort ein Community-Plus Abo abgeschlossen und bin dann ein paar Tage später auf das Unterstützer Abo umgestiegen. Ihr macht eine sehr gute Arbeit und seid jeden Cent wert. Weiter so … ich habe hier so viel gelernt….
Ich bekomme den Fullstack umverrecken nicht zum laufen.
ich mache das ganze über Portainer
die .env Datei wird irgendwie nicht benutzt und ich weis nicht wieso 🙁
muss ich die .env Datei nochmal in die
env_file: /opt/containers/traefik-crowdsec-stack/config/crowdsec.env
mit ein binden damit diese genommen wird ?
hab schon alle Dateien usw. übertragen. Ich will allerdings nicht traefik direkt zugriff auf die docker.sock geben und daher habe ich noch einen docker socket proxy ein gebunden
failed to deploy a stack: Failed to load /opt/containers/traefik-crowdsec-stack/config/crowdsec.env: open /opt/containers/traefik-crowdsec-stack/config/crowdsec.env: no such file or directory
oder kann es sein das ich die env. in den portainer docker legen muss O.ó
das wäre dann aber echt bissel doof
Sehr spannend – ich habe die Anleitung komplett befolgt, um weiterzumachen – und ich bekomme immer:
level=error msg=”middleware \”traefik-crowdsec-bouncer@file\” does not exist” entryPointName=web routerName=web-to-websecure@internal
level=error msg=”middleware \”traefik-crowdsec-bouncer@file\” does not exist” entryPointName=web routerName=acme-http@internal
ich habe die Files mehrfach kontrolliert und bisher bin ich nicht auf den Fehler gestoßen. Beim letzten Mal war es ein Doppelpunkt – aber das ist es hier wohl nicht.
Eine Ergänzung zu den ACME-E-Mail-Adressen. Diese müssen gleich sein, da ansonsten Traefik mit folgender Fehlermeldung abstürzt:
Danke für diese lange, ausführliche Anleitung.
Hat von euch jemand schon eine vorhandene Installation auf diese Anleitung umgestellt? Wie ist der beste Weg ohne große Downtime? Ich bin noch am Grübeln wann und wie ich das migrieren kann. 🙂
Beeindruckende Anleitung. Habe es bereits getestet und soweit funktioniert es.
Wäre so eine angepasste docker-compose für Portainer nach neuer Notation richtig?
Beim Cronjob habe ich das so gemacht.
Beim Nano-Editor ist die Formatierung bei mir recht merkwürdig. Hast du da eine Idee wie das zu beheben ist?
Vielen Dank für die sehr ausführliche Anleitung 😀 Hat bei mir alles direkt funktioniert 👍
Ab Montag werde ich anfangen die alten Beiträge zu migrieren