This Docker image extends the official Caddy server with Cloudflare DNS plugin and security plugins that block hackers, bots and malicious traffic.
- Based on official Caddy server
- Multi-architecture support (linux/amd64, linux/arm64)
- Cloudflare DNS - Automated DNS-01 challenge for wildcard certificates
- Rate Limiting - Protection against brute force and DDoS attacks
- CrowdSec Bouncer - Community-driven threat intelligence
- GeoIP Blocking - Block requests by country
| Plugin | Purpose |
|---|---|
| caddy-dns/cloudflare | DNS-01 ACME challenge via Cloudflare |
| mholt/caddy-ratelimit | Sliding window rate limiting |
| hslatman/caddy-crowdsec-bouncer | CrowdSec integration |
| porech/caddy-maxmind-geolocation | GeoIP-based filtering |
docker pull ghcr.io/mac-lucky/caddy-cloudflare:latest
# or
docker pull maclucky/caddy-cloudflare:latestdocker run -d \
--name caddy \
-p 80:80 \
-p 443:443 \
-v $PWD/Caddyfile:/etc/caddy/Caddyfile \
-v caddy_data:/data \
-v caddy_config:/config \
-e CF_API_TOKEN=your_cloudflare_token \
ghcr.io/mac-lucky/caddy-cloudflare:latest| Variable | Description |
|---|---|
CF_API_TOKEN |
Cloudflare API token with DNS edit permissions |
CROWDSEC_API_KEY |
CrowdSec bouncer API key |
example.com {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
reverse_proxy backend:8080
}Protect against brute force attacks with per-IP rate limits:
(rate_limits) {
rate_limit {
zone dynamic_per_ip {
key {remote_host}
events 100
window 1m
}
zone login_protection {
match {
path /login* /api/auth*
}
key {remote_host}
events 5
window 1m
}
}
}
example.com {
import rate_limits
reverse_proxy backend:8080
}Block malicious IPs using community threat intelligence:
{
crowdsec {
api_url http://crowdsec:8080
api_key {env.CROWDSEC_API_KEY}
ticker_interval 15s
}
}
example.com {
route {
crowdsec
reverse_proxy backend:8080
}
}Block requests from specific countries (requires MaxMind GeoLite2 database):
(geoip_block) {
@blocked_geo {
maxmind_geolocation {
db_path "/usr/share/GeoIP/GeoLite2-Country.mmdb"
deny_countries RU CN KP IR
}
}
handle @blocked_geo {
respond "Access Denied" 403
}
}
example.com {
import geoip_block
reverse_proxy backend:8080
}{
crowdsec {
api_url http://crowdsec:8080
api_key {env.CROWDSEC_API_KEY}
ticker_interval 15s
}
}
(security_headers) {
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
-X-Powered-By
}
}
(rate_limits) {
rate_limit {
zone per_ip {
key {remote_host}
events 100
window 1m
}
}
}
(geoip_block) {
@blocked_geo {
maxmind_geolocation {
db_path "/usr/share/GeoIP/GeoLite2-Country.mmdb"
deny_countries RU CN KP IR
}
}
handle @blocked_geo {
respond "Access Denied" 403
}
}
example.com {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
import security_headers
import rate_limits
import geoip_block
route {
crowdsec
reverse_proxy backend:8080
}
}CrowdSec provides community-driven threat intelligence. To use it:
docker run -d \
--name crowdsec \
-v crowdsec_data:/var/lib/crowdsec/data \
-v crowdsec_config:/etc/crowdsec \
-e COLLECTIONS="crowdsecurity/caddy crowdsecurity/http-cve crowdsecurity/whitelist-good-actors" \
crowdsecurity/crowdsec:latestdocker exec crowdsec cscli bouncers add caddy-bouncerCopy the generated API key and set it as CROWDSEC_API_KEY environment variable.
docker exec crowdsec cscli collections install crowdsecurity/http-cve
docker exec crowdsec cscli collections install crowdsecurity/whitelist-good-actorsGeoIP blocking requires a MaxMind GeoLite2 database:
- Register for free at maxmind.com
- Download
GeoLite2-Country.mmdb - Mount the database file into the container:
docker run -d \
--name caddy \
-v ./GeoLite2-Country.mmdb:/usr/share/GeoIP/GeoLite2-Country.mmdb:ro \
...This image is automatically built and pushed to Docker Hub and GitHub Container Registry daily at midnight UTC.
latest: Latest stable buildx.y.z: Version tagged releases
This project is licensed under the MIT License.