Configuration: abuse protection
This page documents abuse_protection and abuse_event directives for configuring lightweight IP-based abuse protection. When a client exceeds configured thresholds (e.g., rate limit breaches, brute-force failures), Ferron temporarily bans the IP address.
The abuse protection module works by tracking abuse events emitted by other HTTP modules (such as rate limiting and basic authentication) and temporarily banning IPs that exceed configured thresholds within time windows. Bans are stored in memory and automatically expire after the configured duration.
abuse_protection
example.com {
abuse_protection {
ban_duration "15m"
rate_limit_threshold {
events 5
window "300s"
}
brute_force_threshold {
events 3
window "120s"
}
}
}The abuse_protection block can be placed inside an HTTP host block.
| Nested directive | Arguments | Description | Default |
|---|---|---|---|
ban_duration | <duration> | How long to ban an IP. | "15m" (15 minutes) |
rate_limit_threshold | block | Ban after N rate limit events in window. | 5 in 300s |
brute_force_threshold | block | Ban after N brute force failures in window. | 3 in 120s |
custom_threshold | block | Ban after N custom events in window. | none |
error_rate_threshold | block | Ban after N error responses (e.g., 404, 403) in window. | none |
allowlist | <string> [<string> ...] | IP addresses or CIDR ranges exempt from bans. This directive can be specified multiple times. | none |
Threshold blocks
Each threshold block (rate_limit_threshold, brute_force_threshold, custom_threshold) configures when a specific event type triggers a ban:
| Nested directive | Arguments | Description |
|---|---|---|
events | <int> | Number of events required to trigger a ban (required). |
window | <duration> | Time window for counting events (required). |
Error rate threshold block
The error_rate_threshold block configures when error response patterns trigger a ban:
| Nested directive | Arguments | Description | Default |
|---|---|---|---|
events | <int> | Number of error responses required to trigger a ban. | 50 |
window | <duration> | Time window for counting error responses. | "60s" |
status_codes | <string> [<string> ...] | HTTP status codes that count as errors (e.g., "404", "403"). | "404" |
Configuration example — stricter thresholds:
example.com {
abuse_protection {
ban_duration "30m"
rate_limit_threshold {
events 3
window "60s"
}
brute_force_threshold {
events 2
window "120s"
}
}
}Ban after:
- 3 rate limit events in 60s (30-min ban), OR
- 2 brute force failures in 120s (30-min ban)
Configuration example — lenient thresholds:
example.com {
abuse_protection {
ban_duration "5m"
rate_limit_threshold {
events 10
window "600s"
}
brute_force_threshold {
events 10
window "600s"
}
}
}Ban after:
- 10 rate limit events in 10 minutes (5-min ban), OR
- 10 brute force failures in 10 minutes (5-min ban)
Configuration example — trusted IP list:
example.com {
abuse_protection {
allowlist "10.0.0.0/8" "192.168.1.1"
}
}IPs added to the allowlist are never banned, even if they exceed thresholds. This is useful for protecting internal networks, monitoring systems, or other trusted infrastructure.
Configuration example — error rate threshold:
example.com {
abuse_protection {
ban_duration "15m"
error_rate_threshold {
events 10
window "60s"
status_codes "404" "403"
}
}
}Ban after 10 error responses (404 or 403) within 60 seconds. This detects hostile scanning behavior such as probing for old vulnerabilities or non-existent plugin paths.
abuse_event
example.com {
abuse_protection {
ban_duration "15m"
custom_threshold {
events 5
window "300s"
}
}
match WORDPRESS_SCAN {
request.uri.path ~ "/wp-(?:admin|login)(?:.php$|/|$)"
}
if WORDPRESS_SCAN {
abuse_event "wordpress_scan" # <-- register WordPress scanning
}
}The abuse_event block can be placed inside an HTTP host block.
This directive can be used to define custom abuse protection rules (for example, to protect your website from automated vulnerability scanners). This could be also useful when configuring a honeypot within Ferron.
Behavior
Event tracking
The module tracks events per IP address and event type:
- Rate limit events — emitted by the rate limiting module when a client exceeds their rate limit.
- Brute force events — emitted by the basic authentication module when a client has repeated failed authentication attempts.
- Custom events — available for other modules (and
abuse_eventdirective) to emit custom abuse events. - Error rate events — emitted by the abuse protection module itself when a response status code matches configured error codes (e.g., 404, 403). Uses
run_inverseto observe responses after the pipeline completes.
Events are stored in a sliding time window. When the number of events within the window reaches the configured threshold, the IP is immediately banned.
Ban mechanics
- Ban duration — fixed duration (default 15 minutes); independent from the event counting window.
- TTL-based expiry — bans automatically expire after the configured duration; no background eviction threads are needed.
- Per-IP tracking — each IP address is tracked independently. Different event types are tracked separately for the same IP.
- No persistence — bans are stored in memory and are not preserved across server restarts.
If your IP is banned immediately, check configured thresholds — you may have events 1 or events 2, or very short window values (e.g., 10s) that are too aggressive. Reduce the ban_duration to shorten ban times, or increase the events threshold to require more violations before banning.
For manual unbanning, you must wait for the ban to expire naturally.
Request flow
- Client sends a request.
- The abuse protection stage runs early in the pipeline (after
client_ip_from_header, beforerate_limitandbasicauth). - The stage checks if the client’s IP is currently banned.
- If banned: returns 403 Forbidden with a
Retry-Afterheader indicating seconds until ban expiry. - If not banned: request continues through the pipeline normally.
- When other modules detect abuse (rate limit breach, brute force attempt), they emit events to the abuse registry.
- If an event causes a threshold to be exceeded, the IP is immediately banned.
- After the pipeline completes, the abuse protection stage’s
run_inverseobserves the response status code. If it matches a configurederror_rate_thresholdstatus code, an error rate event is recorded.
Allowlist behavior
Any IP that matches an entry in the allowlist is skipped before ban checks are performed. This allows you to protect internal services, monitoring systems, or known-trusted infrastructure from accidental bans.
Examples
Basic abuse protection (defaults)
example.com {
abuse_protection
}Uses default thresholds: bans IPs for 15 minutes if:
- 5 rate limit breaches in 5 minutes, OR
- 3 brute force failures in 2 minutes
Disable abuse protection
example.com {
abuse_protection false
}Observability
Metrics
The abuse protection module emits the following metrics:
| Metric | Type | Attributes | Description |
|---|---|---|---|
ferron.abuseban.rejected | Counter | ferron.abuseban.reason ("rate_limit", "brute_force") | Requests rejected due to IP ban |
ferron.abuseban.triggered | Counter | ferron.abuseban.reason ("rate_limit", "brute_force", "error_rate") | Requests that triggered an IP ban |
Logs
DEBUG: logged when a ban rejection occurs, including the banned IP address and reason.WARN: logged when an IP is triggered for banning.
Structured logs
| Description (summary) | Level | Attributes |
|---|---|---|
| Ban rejection | DEBUG | client.address (client’s IP address), ferron.abuseban.reason ("rate_limit", "brute_force"), ferron.abuseban.remaining_secs (remaining seconds before ban expires) |
| Ban triggered | WARN | client.address (client’s IP address), ferron.abuseban.reason ("rate_limit", "brute_force") |
Access log fields
The abuse protection module contributes the following fields to the HTTP access log line:
| Field | Type | Description |
|---|---|---|
ferron.abuseban.action | string | Action taken: skip (not banned) or rejected (banned). |
ferron.abuseban.reason | string | Ban reason (rejection only). |
ferron.abuseban.remaining_secs | int | Seconds remaining on ban (rejection only). |
Trace spans
The abuse protection stage sets the following attributes on its ferron.stage.abuse_protection span:
| Attribute | Type | Description |
|---|---|---|
ferron.abuseban.action | string | Action taken: skip (not banned) or rejected (banned). |
ferron.abuseban.reason | string | The reason for the ban, when rejected. |
ferron.abuseban.remaining_secs | int | Remaining ban duration in seconds, when rejected. |
error.type | string | Set to ip_banned when the request is rejected, enabling trace UI highlighting. |
See also
Best practices
The following best-practice checks are reported by ferron doctor for directives on this page.
abuse_protection false— Disabling IP banning for repeated abuse events removes a layer of protection. Keep it enabled unless another layer handles abusive clients.allowlistwith wildcard — Exempting every source address from abuse protection should be restricted to known trusted clients.