Configuration
Caddyfile Syntax
The defender
directive is used to configure the Caddy Defender plugin. It has the following syntax:
defender <responder> {
message <custom_message>
ranges <cidr_or_predefined...>
url <url>
}
<responder>
: The responder backend to use.<cidr_or_predefined>
: An optional list of CIDR ranges or predefined range keys to match against the client's IP. Defaults toaws azurepubliccloud deepseek gcloud githubcopilot openai
.<custom_message>
: A custom message to return when using thecustom
responder.<url>
: The URI that theredirect
responder would redirect to.
Supported responder types:
block
: Returns a403 Forbidden
response.custom
: Returns a custom message (requiresmessage
).drop
: Drops the connection.garbage
: Returns garbage data to pollute AI training.redirect
: Returns a308 Permanent Redirect
response (requiresurl
).ratelimit
: Marks requests for rate limiting (requires Caddy-Ratelimit to be installed as well ).tarpit
: Stream data at a slow, but configurable rate to stall bots and pollute AI training.
JSON Configuration
{
"message": "",
"url": "",
"raw_responder": "",
"ranges": [""],
"whitelist": [""],
"tarpit_config": {
"headers": {
"": ""
},
"timeout": 0,
"bytes_per_second": 0,
"code": 0
},
"serve_ignore": false
}
message
- Message specifies the custom response message for
custom
responder type. Required only when usingcustom
responder.
url
- URL specifies the custom URL to redirect clients to for
redirect
responder type. Required only when usingredirect
responder.
raw_responder
- RawResponder defines the response strategy for blocked requests. Required.
- Must be one of the supported responder types, (e.g "block", "drop", etc.).
ranges
- Ranges specifies IP ranges to block, which can be either:
- CIDR notations (e.g., "192.168.1.0/24")
- Predefined service keys (e.g., "openai", "aws") Default:
whitelist
- An optional whitelist of IP addresses to exclude from blocking.
- NOTE: this only supports IP addresses, not ranges.
- If empty, no IPs are whitelisted.
- Default:
[]
tarpit_config
- An optional configuration for the
tarpit
responder - Config holds the tarpit responder`s configuration.
- Default:
{Headers: {}, timeout: 30s, ResponseCode: 200}
tarpit_config/headers
- An optional configuration for the headers to be set with the tarpit config.
- Default:
{}
tarpit_config/timeout
- A Duration represents the elapsed time between two instants as an int64 nanosecond count.
- The representation limits the largest representable duration to approximately 290 years.
tarpit_config/bytes_per_second
- An optional configuration for the default amount of bytes to stream per second.
- Default:
24
.
tarpit_config/code
- An optional configuration for the default response code for the tarpit responder.
- Default:
http.statusOK
serve_ignore
- ServeIgnore specifies whether to serve a robots.txt file with a "Disallow: /" directive.
- Default:
false
For code examples, check out examples.
Embedded IP Ranges
The plugin includes predefined IP ranges for popular AI services. These ranges are embedded in the binary and can be used without additional configuration.
Service | Key | IP Ranges (GitHub) |
---|---|---|
Alibaba Cloud | aliyun | aliyun.go |
VPNs | vpn | vpn.go |
AWS | aws | aws.go |
AWS Region | aws-us-east-1, aws-us-west-1, aws-eu-west-1 | aws_region.go |
DeepSeek | deepseek | deepseek.go |
GitHub Copilot | githubcopilot | github.go |
Google Cloud Platform | gcloud | gcloud.go |
Oracle Cloud Infrastructure | oci | oracle.go |
Microsoft Azure | azurepubliccloud | azure.go |
OpenAI | openai | openai.go |
Mistral | mistral | mistral.go |
Vultr | vultr | vultr.go |
Cloudflare | cloudflare | cloudflare.go |
Digital Ocean | digitalocean | digitalocean.go |
Linode | linode | linode.go |
Private | private | private.go |
All IP addresses | all | all.go |
Disabled by default (require manual inclusion at build time)
Service | Key | IP Ranges (GitHub) |
---|---|---|
Tor Exit Nodes | tor | tor.go |
ASN (Autonomous System Numbers) | asn | asn.go |
More are welcome! For a precompiled list, see the embedded results.
Rate Limiting Configuration
Feature: Match requests by IP range and apply rate limiting using caddy-ratelimit.
Caddyfile Syntax
defender ratelimit {
ranges <cidr_or_predefined...>
}
rate_limit {
# Match requests marked by Defender
match header X-Defender-RateLimit true
# Rate limiting parameters
rate <requests-per-second>
burst <burst-size>
key <rate-limit-key>
}
JSON Configuration
{
"handler": "defender",
"raw_responder": "ratelimit",
"ranges": ["aws", "10.0.0.0/8"],
"rate_limit_header": "X-Defender-RateLimit"
}
Example Configurations
Basic Configuration
example.com {
defender ratelimit {
ranges cloudflare openai
}
rate_limit {
match header X-Defender-RateLimit true
rate 5r/s
burst 10
key {http.request.remote.host}
}
respond "Hello World"
}
Advanced Configuration
api.example.com {
defender ratelimit {
ranges 192.168.1.0/24 azure
rate_limit_header X-API-RateLimit
}
rate_limit {
match header X-API-RateLimit true
rate 10r/s
burst 20
key {http.request.uri.path}
# Optional: Custom response
respond {
status_code 429
body "Too Many Requests - Try Again Later"
}
}
reverse_proxy localhost:3000
}
Documentation
Directives
Defender Rate Limit Responder:
ranges
- IP ranges to apply rate limiting (CIDR or predefined)rate_limit_header
(optional) - Header to mark requests for rate limiting (default:X-Defender-RateLimit
)
Rate Limit Module:
match header
- Match the header set by Defenderrate
- Requests per second (e.g.,10r/s
)burst
- Allow temporary bursts of requestskey
- Rate limit key (typically client IP or path)
How It Works
- IP Matching: Defender checks if client IP matches configured ranges
- Header Marking: Matching requests get a header (
X-Defender-RateLimit: true
) - Rate Limiting: caddy-ratelimit applies limits only to marked requests
- Request Processing: Non-matched requests bypass rate limiting
Use Cases
- Protect API endpoints from scraping
- Mitigate brute force attacks
- Enforce different rate limits for:
- Different geographic regions
- Known bot networks
- Internal vs external traffic
Requirements
- caddy-ratelimit module installed
- caddy-defender v0.5.0+
Notes
- Order Matters: Defender must come before ratelimit in handler chain
- Header Customization: Change header name if conflicts occur
- Combination with Other Protections:
defender ratelimit {
ranges aws
}
rate_limit {
match header X-Defender-RateLimit true
rate 2r/s
}
defender block {
ranges known-bad-ips
}
Troubleshooting
1. Check Headers:
curl -I http://example.com
2. Verify Handler Order: Defender → Ratelimit → Other handlers
3. Test Rate Limits:
# Simulate requests from blocked range
for i in {1..20}; do
curl -H "X-Forwarded-For: 20.202.43.67" http://example.com
done