Snorre.io

Protecting Traefik proxy with CrowdSec

I’ve been using Traefik as a reverse proxy for many years now. It’s an open-source proxy with powerful features and a great community. They were even kind enough to send me a t-shirt once for one of my blog posts, so I’m a bit biased. Recently I’ve been running Crowdsec as a firewall and intrusion detection system. Until now I’ve been content protecting against SSH brute force attacks and relying on their IP blocklists to protect against malicious actors. But now that I host more of my own services on VMs behind Traefik, I decided it was time to protect against HTTP attacks as well. Fortunately, Crowdsec has facilities for handling Traefik HTTP traffic, and in this post I’ll show you my setup.

The Traefik access log

To protect against common HTTP brute force attacks, we need to be able to detect them. Crowdsec is largely based around parsing and analysing logs, tracking the number of events over time to determine the IP addresses that are most likely to be malicious actors. Traefik has a built-in access log that can be used to feed into Crowdsec. Some of the most relevant fields in the access logs are shown below. By extracting these fields Crowdsec can determine the IP address of the malicious actor and take action based on the patterns it finds.

{
    "ClientHost": "<client-ip>",
    "RequestMethod": "GET",
    "RequestPath": "/some/path",
    "RequestHost": "<external-domain>",
    "DownstreamStatus": 400,
    "RequestProtocol": "HTTP/2.0",
    "time": "2026-01-25T16:18:38Z"
}

To configure the access log, we need to set the accessLog section in the Traefik configuration file.

accessLog:
  filePath: /opt/traefik/logs/access.log
  format: json

If you run Traefik inside Docker, you’ll want to mount the log file to the host filesystem so it can be read by Crowdsec.

volumes:
  - /opt/traefik/logs/access.log:/opt/traefik/logs/access.log

Log rotation

Traefik only supports rotation of its own service logs, not the access log. In order to rotate the access log you can use the logrotate service to rotate the log file. Here is an example configuration for the logrotate service:

/opt/traefik/logs/access.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0644 root root
    sharedscripts
    postrotate
        # Send USR1 signal to Traefik to reopen log file
        docker kill --signal="USR1" $(docker ps | grep traefik | awk '{print $1}') 2>/dev/null || true
    endscript
}

I use the postrotate directive to send a USR1 signal to Traefik to reopen the log file. This is necessary because logrotate will move the log file to access.log.1, access.log.2, etc. Traefik would append to its open file descriptor indefinitely, causing it to write to the moved file under access.log.1, access.log.2, etc. Sending the USR1 signal to Traefik causes it to reopen the log file and start appending to the new file.

Setting up Crowdsec to analyze Traefik access logs

Crowdsec has a collection that provides the log parser for Traefik access logs and includes base HTTP scenarios to protect against. These scenarios include:

  • aggressive crawl detection
  • scanning/probing detection
  • bad user-agent detection
  • path traversal detection
  • sensitive data access attempts detection
  • SQL injection detection
  • administration interface probing detection

You can install it using the following command:

cscli collections install crowdsecurity/traefik

For Crowdsec to analyse the logs, you need to set up an acquisition target for the logs, for example at /etc/crowdsec/acquis.d/traefik.yaml:

filenames:
  - /opt/traefik/logs/access.log
labels:
  type: traefik

The scenarios should be enabled by default when installing the collection. You can verify this by checking the cscli scenarios list command.

After enabling the scenarios on multiple VMs of mine I’ve already seen a few malicious actors get banned:

Crowdsec decisions page showing rows of decisions made by Crowdsec banning malicious http traffic

A word of caution

The default http-probing scenario is quite aggressive, banning IPs that generate too many 400-range responses in a short period of time. I managed to get my own IP banned by this scenario after pushing Docker images to my Forgejo registry. This was caused by docker push making multiple requests to check for the existence of layers, resulting in a cascade of 404 responses that triggered the scenario.

To avoid this, you can either disable the specific scenario or create a custom configuration to exclude certain paths or adjust the thresholds. You could define a custom /etc/crowdsec/scenarios/http-probing-override.yaml file that excludes the /v2/ path from the scenario and allows up to 100 400-range requests per IP within 30 seconds:

type: leaky
name: crowdsecurity/http-probing-override
description: "Override for http-probing scenario with much higher threshold to reduce false positives"
filter: "evt.Meta.service == 'http' && evt.Meta.http_status in ['404', '403', '400'] && evt.Parsed.static_ressource == 'false' && !(evt.Parsed.http_path matches '^/v2/')"
leakspeed: 30s
capacity: 100
groupby: "evt.Meta.source_ip + evt.Meta.http_target_fqdn"
distinct: "evt.Parsed.http_path"
blackhole: 5m
labels:
  service: http
  type: scan

Conclusion

With a few quick steps, I was able to set up Crowdsec to ban malicious actors from accessing my VMs. Note that this setup is not a replacement for a Web Application Firewall (WAF), as it does not block attacks at the application layer. Instead, it analyses the logs and takes action based on the patterns it finds. This makes it a good complement to a WAF, providing additional protection against common HTTP attacks. Another positive aspect of this setup is that Crowdsec shares the IP of the attackers with the entire Crowdsec network. This way other Crowdsec users can benefit from the information and take action against the same malicious actors without first having to identify them.

If you need a WAF, you can check out Crowdsec WAF, which sits as a component inside your Traefik proxy. This allows you to block attacks at the application layer and block malicious actors in the proxy layer. Note that blocking at the network layer via your firewall is better, as traffic never reaches the proxy layer and thus reduces computational overhead. Fortunately, Crowdsec WAF can be used in conjunction with your firewall to provide additional protection.