Skip to content

Configuration Reference

Fabrizio Salmi edited this page Sep 6, 2026 · 1 revision

Configuration reference

Required

Directive Meaning Example
error_codes Space-separated HTTP status codes to count error_codes 404 500 401
max_error_count Errors from one IP before a ban max_error_count 10
ban_duration Initial ban length, human readable ban_duration 5s, 10m, 1h

Optional

Directive Default Meaning
ban_duration_multiplier 1.0 Multiplies the ban length on each repeat offence. 1.5 grows it, 1 keeps it flat
error_count_timeout disabled Sliding window. If the gap between two errors exceeds this, the count restarts at 1. See How banning works
whitelist empty IPs and CIDRs that are never banned. whitelist 127.0.0.1 ::1 192.168.1.0/24
cidr_bans empty CIDR ranges banned outright. cidr_bans 10.0.0.0/8 172.16.0.0/12
ban_status_code 403 Status returned to a banned client. Only 403 or 429 are accepted
ban_response_body empty Response body for banned clients. Without it the body is empty
custom_response_header none Comma-separated values added to the response, each under the key X-Custom-MIB-Info
log_request_headers none Request headers to include in the log line when an IP is banned. log_request_headers User-Agent X-Forwarded-For
log_level Caddy's global level debug, info, warn or error for this middleware only

Per-path blocks

per_path <path> overrides the global settings for one path, and accepts the same options: error_codes, max_error_count, ban_duration, ban_duration_multiplier and error_count_timeout.

caddy_mib {
    error_codes 404 500 401
    max_error_count 10
    ban_duration 5s

    per_path /login {
        error_codes 404
        max_error_count 5
        ban_duration 10s
        ban_duration_multiplier 2
        error_count_timeout 15m
    }

    per_path /api {
        error_codes 404 500
        max_error_count 8
        ban_duration 15s
    }
}

Two things to keep in mind:

  • Path bans and the global ban are counted separately. An IP can exhaust the /login budget and be banned there while still under the global limit elsewhere.
  • error_count_timeout is inherited from the global block when a per-path block does not set it. The other options are not inherited in a way you should rely on: set explicitly what matters for that path.

A full example

{
    admin off
    log {
        level debug
        output stdout
        format console
    }
}

:8080 {
    route {
        caddy_mib {
            error_codes 404 500 401
            max_error_count 10
            ban_duration 5s
            ban_duration_multiplier 1.5
            error_count_timeout 1h
            whitelist 127.0.0.1 ::1 192.168.1.0/24
            cidr_bans 10.0.0.0/8
            ban_status_code 429
            ban_response_body "You have been temporarily blocked due to excessive errors."
            log_request_headers User-Agent X-Forwarded-For
            log_level debug

            per_path /login {
                error_codes 404
                max_error_count 5
                ban_duration 10s
                ban_duration_multiplier 2
                error_count_timeout 15m
            }
        }

        handle {
            respond "Hello world!" 404
        }
    }
}

Clone this wiki locally