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 (for example, rate limit breaches or brute-force failures), Ferron temporarily bans the IP address.
The abuse protection module tracks abuse events that other HTTP modules emit. These modules include rate limiting and basic authentication. It temporarily bans IPs that exceed configured thresholds within time windows. The system stores bans in memory and they 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"
}
}
}You can place the abuse_protection block 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 (for example, 404, 403) in window. | none |
allowlist | <string> [<string> ...] | IP addresses or CIDR ranges exempt from bans. You can specify this directive 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 (for example, "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"
}
}Ferron never bans IPs in the allowlist, 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
}
}You can place the abuse_event block inside an HTTP host block.
You can use this directive to define custom abuse protection rules. For example, it can protect your website from automated vulnerability scanners. It is also useful when configuring a honeypot within Ferron.
Behavior#
Event tracking#
The module tracks events per IP address and event type:
- Rate limit events: the rate limiting module emits them when a client exceeds its rate limit.
- Brute force events: the basic authentication module emits them 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: the abuse protection module emits them when a response status code matches configured error codes. For example, 404 and 403. It uses
run_inverseto observe responses after the pipeline completes.
The system stores events in a sliding time window. When the number of events within the window reaches the configured threshold, the system immediately bans the IP.
Ban mechanics#
- Ban duration: fixed duration (default 15 minutes). It is independent from the event counting window.
- TTL-based expiry: bans automatically expire after the configured duration. The system needs no background eviction threads.
- Per-IP tracking: the module tracks each IP address independently. It tracks different event types separately for the same IP.
- No persistence: the system stores bans in memory. They are not preserved across server restarts.
If the system bans your IP immediately, check configured thresholds. You may have events 1 or events 2, or very short window values (for example, 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.
Allowlist behavior#
The stage skips any IP that matches an entry in the allowlist before it runs ban checks. 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. The message includes the banned IP address and reason.WARN: logged when the module triggers a ban for an IP.
Structured logs#
| Description (summary) | Level | Attributes |
|---|---|---|
| Ban rejection | DEBUG | client.address (client IP address), ferron.abuseban.reason ("rate_limit", "brute_force"), ferron.abuseban.remaining_secs (remaining seconds before ban expires) |
| Ban triggered | WARN | client.address (client 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 Ferron rejects the request, enabling trace UI highlighting. |
See also#
Best practices#
ferron doctor reports the following best-practice checks 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 apply only to known trusted clients.