This folder contains a ready‑to‑use Traefik v3 setup with CrowdSec. It helps you put a secure reverse proxy in front of your apps.
Note: The dynamic_host folder is work in progress. Ignore it for now.
- Traefik (reverse proxy) with HTTPS via Let’s Encrypt.
- CrowdSec (blocks bad IPs; reads Traefik access logs).
- A small test app (
whoami). - Log rotation for Traefik logs.
Main files:
docker-compose.yml— starts Traefik, CrowdSec, and logrotate.traefik.yml— Traefik static config (entry points, ACME, plugin).traefik_dynamic.yml— Traefik dynamic config (CrowdSec middleware).crowdsec/config/acquis.yaml— tells CrowdSec where to read logs.test_conteneur/docker-compose.yml— demo service with Traefik labels.
- Create the Docker network (Traefik uses it):
docker network create frontend- Prepare Let’s Encrypt storage file and copy dynamic conf :
mkdir -p letsencrypt traefik_logs
cp traefik_dynamic_exemple.yml traefik_dynamic.yml- Start Traefik + CrowdSec:
docker compose up -d- Create a CrowdSec bouncer key (copy the printed key):
docker exec -t crowdsec cscli bouncers add traefik-bouncer- Install the Traefik collection in CrowdSec:
docker exec -t crowdsec cscli collections install crowdsecurity/traefik- Put the key in
traefik_dynamic.yml:
- Edit
crowdsecLapiKey: "YOUR_GENERATED_BOUNCER_API_KEY_FROM_CROWDSEC". - Save the file.
- docker compose down && docker compose up -d.
- Verify CrowdSec reads the logs:
docker exec -t crowdsec cscli metrics- Set your domain shell variable (replace with your real domain):
export DOMAIN=example.com- Start the test service:
cd test_conteneur
DOMAIN=$DOMAIN docker compose up -d- Check it in a browser:
- Open:
https://example.com(replace with your domain) - The certificate comes from Let’s Encrypt.
- See CrowdSec status:
docker exec -t crowdsec cscli bouncer list- Traefik listens on ports 80 (HTTP) and 443 (HTTPS).
- All HTTP (80) is redirected to HTTPS (443).
- Let’s Encrypt issues certificates using TLS‑ALPN challenge.
- Traefik writes access logs in
./traefik_logs. - CrowdSec reads these logs and decides which IPs to block.
- The Traefik plugin
crowdsec-bouncer-traefik-pluginapplies the block. - The middleware is attached globally to
websecureand can also be added per‑router.
- Check Metrics and file acquisition:
docker exec -t crowdsec cscli metrics- List CrowdSec collections:
docker exec -t crowdsec cscli collections list- List decisions (bans):
docker exec -t crowdsec cscli decisions list- Manually ban/unban an IP:
docker exec -t crowdsec cscli decisions add --ip 1.2.3.4
docker exec -t crowdsec cscli decisions delete -i 1.2.3.4- Manually trust an IP: #TODO: Check the best option ?
# config : whitlelist uniquement ce qui est lu dans le fichier de log
nano TraefikV3/crowdsec/config/parsers/s02-enrich/whitelists-custom.yaml
# allowlist : plus générique et englobant
docker exec -it crowdsec cscli allowlists create my_allowlist -d 'my allowlist'
docker exec -it crowdsec cscli allowlist add my_allowlist 172.18.0.0/24
cscli allowlist inspect my_allowlist- Check Traefik logs:
tail -f traefik_logs/access.log- List and inspect alert :
docker exec -t crowdsec cscli alert list
docker exec -t crowdsec cscli alerts inspect -d 56-
traefik.yml- Docker provider enabled. Only containers with
traefik.enable=trueare exposed. - File provider watches
traefik_dynamic.yml. - Global middleware on
websecureadds CrowdSec protection by default. - Let’s Encrypt: storage in
./letsencrypt/acme.json, TLS challenge enabled. - Access logs in JSON, both success and error ranges recorded.
- CrowdSec plugin declared in
experimental.plugins.
- Docker provider enabled. Only containers with
-
traefik_dynamic.yml- Defines
middlewares.crowdsecusing the Traefik CrowdSec bouncer plugin. - Replace the API key with the one you generated.
- AppSec is disabled (you can enable it if you run CrowdSec AppSec).
- Defines
-
docker-compose.yml- Mounts Docker socket read‑only (good practice).
- Persists Let’s Encrypt data and logs to host.
- CrowdSec reads Traefik logs and uses the same
frontendnetwork. logrotaterotates Traefik logs daily and keeps 7 copies.
-
crowdsec/config/acquis.yaml- Tells CrowdSec to read
/var/log/traefik/access.logwith labeltype: traefik.
- Tells CrowdSec to read
-
test_conteneur/docker-compose.yml- Example labels for router, TLS resolver, and middleware.
- Uses
$DOMAINfor the host rule.
-
Traefik image tag
traefik:chabichou:- This is the latest as I write these lines. Check back regularly.
-
Public email in config:
traefik.ymlcontains an email for Let’s Encrypt. If this repo is public, consider moving it to an env var.
-
Secrets in plain text:
crowdsecLapiKeyis stored in a file. Consider using an env var or a mounted secret (${CROWDSEC_LAPI_KEY}) and reference it in the dynamic file.
-
Resource limits and security options:
- No CPU/RAM limits are set. You can add
deploy.resources.limits(Swarm) or--cpus/--memory(Compose v2) where needed. - Consider adding
read_only: trueand dropping capabilities where possible, plus healthchecks.
- No CPU/RAM limits are set. You can add
-
Network note:
- The
frontendnetwork is markedexternal: true. You must create it before starting services.
- The
-
Logs and rotation:
- Rotation is present. Make sure
traefik_logshas enough disk space and correct permissions.
- Rotation is present. Make sure
-
Plugin pinning:
- The CrowdSec plugin is pinned to
v1.4.5. Keep it updated to the latest stable when you can.
- The CrowdSec plugin is pinned to
-
CrowdSec AppSec:
- AppSec is disabled (
crowdsecAppsecEnabled: false). Enable it only if you deploy the AppSec component and configure it properly.
- AppSec is disabled (
If all the above points are fine for your context, the setup is OK.
-
Certificates are not created:
- Check DNS for your domain points to this server.
- Ensure port 443 is open and reachable from the Internet.
- Read Traefik logs in
traefik_logs/access.logand Traefik container logs.
-
CrowdSec shows no metrics:
- Ensure Traefik writes logs to
/var/log/traefikin the container. - Check that
crowdsec/config/acquis.yamlpoints to the correct path.
- Ensure Traefik writes logs to
-
404 or wrong router:
- Check your labels (spelling matters).
- Confirm the container is on the
frontendnetwork.
docker compose down
cd test_conteneur && docker compose downSee LICENSE.