A Caddy module that blocks malicious traffic based on decisions made by CrowdSec.
The Caddy CrowdSec Bouncer consists of five components:
caddy crowdsec Command: Offers useful Caddy CLI commands for your CrowdSec integration.CrowdSec is a free and open source security automation tool that uses local logs and a set of scenarios to infer malicious intent. In addition to operating locally, an optional community integration is also available, through which crowd-sourced IP reputation lists are distributed.
The architecture of CrowdSec is very modular. At its core is the CrowdSec Security Engine, which keeps track of all data and related systems. Bouncers are pieces of software that perform specific actions based on the decisions of the Security Engine.
[!TIP] You can find full setup examples in /examples inside this repository.
You can use the bouncer by either building a custom Caddy image with Docker or by fetching the required Go modules directly into your own build.
Note: You will need a recent version of Caddy (v2.7.3+) and Go (1.20+).
To include the bouncer in a Docker Image using xcaddy. Create a Dockerfile:
1ARG CADDY_VERSION=223FROM caddy:${CADDY_VERSION}-builder-alpine AS builder45RUN xcaddy build \6 --with github.com/mholt/caddy-l4 \7 --with github.com/caddyserver/transform-encoder \8 --with github.com/hslatman/caddy-crowdsec-bouncer/http@main \9 --with github.com/hslatman/caddy-crowdsec-bouncer/appsec@main \10 --with github.com/hslatman/caddy-crowdsec-bouncer/layer4@main1112FROM caddy:${CADDY_VERSION}1314COPY --from=builder /usr/bin/caddy /usr/bin/caddy
If you are compiling outside of Docker, you can fetch the modules using go get:
1# get the CrowdSec Bouncer HTTP handler2go get github.com/hslatman/caddy-crowdsec-bouncer/http34# get the CrowdSec layer4 connection matcher (only required for TCP/UDP level blocking)5go get github.com/hslatman/caddy-crowdsec-bouncer/layer467# get the AppSec HTTP handler (only required for CrowdSec AppSec support)8go get github.com/hslatman/caddy-crowdsec-bouncer/appsec
Configuration using a Caddyfile is supported for HTTP handlers and Layer 4 matchers.
| Directive | Description | Default |
|---|---|---|
api_url | The URL of the CrowdSec Local API. | http://127.0.0.1:8080/ |
api_key | The API key to authenticate with the Local API. | <empty> (required) |
disable_streaming | Falls back to LiveBouncer mode (queries API per request). | false |
metrics_interval | Interval for pushing metrics to the Local API. | 0s (disabled) |
enable_caddy_metrics | Enables emitting bouncer metrics at Caddy's /metrics endpoint. | false |
ticker_interval | Interval for pulling decisions from the Local API. | 60s |
enable_hard_fails | Caddy fails to start if CrowdSec API is unreachable. | false |
appsec_url | The URL of the CrowdSec AppSec component. | <empty> (disabled) |
appsec_max_body_bytes | Maximum request body size sent to AppSec. | 0 (full request) |
appsec_max_timeout. | Maximum time for request to AppSec component. | 2s |
appsec_fail_open | Ignore AppSec component connection errors. | false |
enable_caddy_error | Propagates decisions as Caddy errors to allow custom error pages. Warning: Ensure handle_errors routes are strictly static to avoid resource exhaustion (DoS). | false |
1{2 debug34 crowdsec {5 api_url http://localhost:80806 api_key <api_key>7 ticker_interval 15s8 appsec_url http://localhost:74229 #disable_streaming10 #enable_hard_fails11 #enable_caddy_error12 }1314 layer4 {15 localhost:4444 {16 @crowdsec crowdsec17 route @crowdsec {18 proxy {19 upstream localhost:644320 }21 }22 }23 }24}2526localhost:8443 {27 route {28 crowdsec29 respond "Allowed by Bouncer!"30 }31}3233localhost:7443 {34 route {35 appsec36 respond "Allowed by AppSec!"37 }38}3940localhost:6443 {41 route {42 crowdsec43 appsec44 respond "Allowed by Bouncer and AppSec!"45 }46}
Run the Caddy server
1# with a Caddyfile2caddy run --config Caddyfile
This repository also contains an example using Docker inside the examples/demo folder. Steps to run this demo are as follows:
1# run CrowdSec container2docker compose up -d crowdsec34# add the Caddy bouncer, generating an API key5docker compose exec crowdsec cscli bouncers add caddy-bouncer67# copy and paste the API key in the ./examples/demo/config.json file89# run Caddy; at first run a custom build will be created using xcaddy10docker compose up -d caddy1112# tail the logs13docker compose logs -tf
You can then access https://localhost:9443 and https://localhost:8443. The latter is an example of using the Layer 4 App and will simply proxy to port 9443 in this case.
When Caddy is built with this module enabled, a new caddy crowdsec command will be enabled.
Its subcommands allow you to interact with your CrowdSec integration at runtime using Caddy's Admin API.
This is useful to verify the status of your integration, and check if it's configured and working properly.
The command requires the Admin API to be reachable from the system it is run from.
Support for the command is currently experimental, and will be improved and extended in future releases. Output of the commands should not be relied upon in automated processes (yet).
1$ caddy crowdsec23Commands related to the CrowdSec integration (experimental)45Usage:6 caddy crowdsec [command]78Available Commands:9 check Checks an IP to be banned or not10 health Checks CrowdSec integration health11 info Shows CrowdSec runtime information12 ping Pings the CrowdSec LAPI endpoint1314Flags:15 -a, --adapter string Name of config adapter to apply (when --config is used)16 --address string The address to use to reach the admin API endpoint, if not the default17 -c, --config string Configuration file to use to parse the admin address, if --address is not used18 -h, --help help for crowdsec19 -v, --version version for crowdsec2021Use "caddy crowdsec [command] --help" for more information about a command.2223Full documentation is available at:24https://caddyserver.com/docs/command-line
When your Caddy server is deployed behind a proxy (like a CDN or load balancer), the actual client IP is masked. Starting with v0.3.1, this module relies on Caddy's native logic (introduced in Caddy v2.7.0 via caddy#5104) to determine the correct client IP before checking it against CrowdSec decisions.
Important: Caddy uses the
X-Forwarded-Forheader by default. To trust this header, you must configure thetrusted_proxiesglobal directive in your Caddyfile.
You can override the default header using the client_ip_headers directive.
Note: For Caddy versions up to v2.4.6 and older versions of this module, the realip module is required.
...and more things to come!
We are always open to contributions! Whether it's fixing bugs, improving documentation, or adding new features from the Roadmap above, your help is welcome. Feel free to open an issue or submit a pull request.