🐳 The Caddy Docker image built with the Cloudflare DNS module and CrowdSec bouncers
76
The Caddy Docker image with the added
Built for the same platforms as the upstream Caddy project (except Windows, sorry)!
Note
This image does not change anything with original Caddy Docker image except replace the `caddy` binary.
# Docker Hub
docker pull 580132/caddy-cloudflare-crowdsec:latest
# GHCR
docker pull ghcr.io/580132/caddy-cloudflare-crowdsec:latest
The following tags are the latest available for the
580132/caddy-cloudflare-crowdsec image.
Check the GitHub Tags for a list of all versions!
Since this is built off the official Docker image all of the same Volumes, Environment variables, etc. can be used with this container. Please refer to the official Caddy Docker image and docs for more information on using Caddy.
Simply create the container as usual and include your CF_API_TOKEN (email no
longer required for API Tokens). We can utilize Caddy's support for
Environment varaiables
to pass these values into our Caddyfile.
Important
Be sure to create your `Caddyfile` beforehand to avoid Docker startup errors.
docker run --rm -it \
--name caddy \
-p 80:80 \
-p 443:443 \
-v caddy_data:/data \
-v caddy_config:/config \
-v $PWD/Caddyfile:/etc/caddy/Caddyfile \
-e CF_API_TOKEN=UhKLc...JD9jk \
580132/caddy-cloudflare-crowdsec:latest
If you prefer docker-compose you can use the provided
docker-compose.yml after updating it with your
CF_API_TOKEN.
docker compose up
Set the global
acme_dns directive
in your Caddyfile
{
acme_dns cloudflare {env.CF_API_TOKEN}
}
or via JSON
{
"module": "acme",
"challenges": {
"dns": {
"provider": {
"name": "cloudflare",
"api_token": "{env.CF_API_TOKEN}"
}
}
}
}
See the caddy-dns/cloudflare module
and tls directive
for advanced usage.
The image bundles the CrowdSec bouncer for Caddy, which blocks malicious traffic based on the decisions made by your CrowdSec Security Engine.
| Module | Directive | Purpose |
|---|---|---|
http | crowdsec | Checks the client IP of incoming HTTP requests against CrowdSec decisions |
appsec | appsec | Checks incoming HTTP requests against the rulesets of a CrowdSec AppSec component |
layer4 | crowdsec (matcher) | Matches TCP/UDP IP addresses against the CrowdSec Local API, for non-HTTP traffic |
All three share a single Caddy app, so the Local API credentials only have to be configured once in the global options.
Declare the crowdsec global option, then use the crowdsec directive in
your site block:
{
crowdsec {
api_url http://crowdsec:8080
api_key {env.CROWD_SEC_API_KEY}
ticker_interval 15s
}
}
example.com {
route {
crowdsec
reverse_proxy localhost:3000
}
}
The api_key is the value of a bouncer registered on your CrowdSec instance:
docker exec crowdsec cscli bouncers add caddy-bouncer
| Option | 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. | required |
disable_streaming | Falls back to LiveBouncer mode (queries the API per request). | false |
ticker_interval | Interval for pulling decisions from the Local API. | 60s |
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 |
enable_hard_fails | Caddy fails to start if the CrowdSec API is unreachable. | false |
appsec_url | The URL of the CrowdSec AppSec component. | disabled |
appsec_max_body_bytes | Maximum request body size sent to AppSec. | 0 (full request) |
appsec_max_timeout | Maximum time for a request to the 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. | false |
Warning
When enabling `enable_caddy_error`, make sure `handle_errors` routes are strictly static, to avoid resource exhaustion (DoS).
If you run a CrowdSec AppSec
component, point the bouncer at it and add the appsec directive:
{
crowdsec {
api_url http://crowdsec:8080
api_key {env.CROWD_SEC_API_KEY}
appsec_url http://crowdsec-appsec:7422
}
}
example.com {
route {
crowdsec
appsec
reverse_proxy localhost:3000
}
}
The Layer 4 matcher blocks TCP and UDP traffic by IP address, using the caddy-l4 app:
{
crowdsec {
api_url http://crowdsec:8080
api_key {env.CROWD_SEC_API_KEY}
}
layer4 {
:443 {
@crowdsec crowdsec
route @crowdsec {
proxy {
upstream localhost:8443
}
}
}
}
}
The bouncer relies on Caddy's native client IP detection. Caddy uses the
X-Forwarded-For header by default, so if you run behind a proxy or CDN you
must configure the
trusted_proxies
global directive, otherwise every request will be checked against the proxy's
IP address.
{
trusted_proxies static private_ranges
}
The HTTP and AppSec handlers record why a request was blocked, so matchers and logs can tell blocks apart:
| Variable | Description | Examples |
|---|---|---|
{http.vars.crowdsec.module} | The handler that blocked the request. | http, appsec |
{http.vars.crowdsec.remediation} | The remediation that was applied. | ban, captcha, throttle |
{http.vars.crowdsec.origin} | The origin of the decision. | appsec, crowdsec, lists:foo |
{http.vars.crowdsec.duration} | The duration of the decision. | 3h59m58s |
handle_errors {
log_append blocked-by {http.vars.crowdsec.module}
}
Building Caddy with the bouncer also enables the caddy crowdsec command, which
talks to the Caddy Admin API to inspect the integration:
caddy crowdsec health # check the integration health
caddy crowdsec info # show runtime information
caddy crowdsec ping # ping the Local API endpoint
caddy crowdsec check <IP> # check whether an IP is banned
Note
The `caddy crowdsec` command is currently experimental.
You can generate a Cloudflare API token via the Cloudflare web console using the following steps:
Zone > Zone > ReadZone > DNS > EditYou can easily build the Docker image locally by doing
docker build -t caddy-cloudflare-crowdsec .
If you prefer docker-compose you can use the provided
docker-compose.yml for building
docker compose build
All container images will be automatically signed via Cosign using keyless signatures. You can use the following command to verify the integrity of these images yourself.
cosign verify \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp https://github.com/580132/caddy-cloudflare-crowdsec/.github/workflows/ \
580132/caddy-cloudflare-crowdsec:latest
Feel free to contribute and make things better by opening an Issue or Pull Request.
See LICENSE.
Content type
Image
Digest
sha256:53fba11f6…
Size
42.1 MB
Last updated
8 days ago
docker pull 580132/caddy-cloudflare-crowdsec