Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Traffic Control Middlewares

Plugins that decide whether a request makes it to the dispatcher at all — rate limits, CORS, IP allow/deny, bot patterns, payload size caps.


rate-limit

Limits request rate per client using a sliding window algorithm. Implements IETF draft-ietf-httpapi-ratelimit-headers.

x-barbacane-middlewares:
  - name: rate-limit
    config:
      quota: 100
      window: 60
      policy_name: default
      partition_key: client_ip

Configuration

PropertyTypeDefaultDescription
quotaintegerrequiredMaximum requests allowed in the window
windowintegerrequiredWindow duration in seconds
policy_namestringdefaultPolicy name for RateLimit-Policy header and the rate-limit bucket-key prefix
partition_keystringclient_ipRate limit key source

Partition key sources

  • client_ip — Client IP from X-Forwarded-For or X-Real-IP
  • header:<name> — Header value (e.g., header:X-API-Key)
  • context:<key> — Context value set by an upstream middleware (e.g., context:auth.sub)
  • Any static string — same limit for all requests sharing that string

Response headers

On allowed requests:

  • X-RateLimit-Policy — Policy name and configuration
  • X-RateLimit-Limit — Maximum requests in window
  • X-RateLimit-Remaining — Remaining requests
  • X-RateLimit-Reset — Unix timestamp when window resets

The same four headers are also set on the request forwarded to the upstream. When instances are stacked, the response reports the policy with the fewest requests remaining, and a 429 from one of them carries only that policy’s RateLimit headers below, not the X-RateLimit-* of the policies that allowed the request.

On rate-limited requests (429):

  • RateLimit-Policy — IETF draft header
  • RateLimit — IETF draft combined header
  • Retry-After — Seconds until retry is allowed

Layered rate limits (stacking)

Stack multiple instances with **distinct policy_name**s to enforce layered limits — for example, a per-IP burst cap and a per-user daily budget:

x-barbacane-middlewares:
  - name: rate-limit
    config:
      policy_name: per-ip-burst
      quota: 100
      window: 60
      partition_key: client_ip
  - name: rate-limit
    config:
      policy_name: per-user-daily
      quota: 10000
      window: 86400
      partition_key: "context:auth.sub"

policy_name is also the bucket-key prefix. If two stacked instances share a policy_name, they share the bucket — only the tighter of the two will be effective. Always override policy_name when stacking.


cors

Handles Cross-Origin Resource Sharing per the Fetch specification. Processes preflight OPTIONS requests and adds CORS headers to responses.

x-barbacane-middlewares:
  - name: cors
    config:
      allowed_origins:
        - https://app.example.com
        - https://admin.example.com
      allowed_methods:
        - GET
        - POST
        - PUT
        - DELETE
      allowed_headers:
        - Authorization
        - Content-Type
      expose_headers:
        - X-Request-ID
      max_age: 86400
      allow_credentials: false

Configuration

PropertyTypeDefaultDescription
allowed_originsarray[]Allowed origins (["*"] for any, or specific origins)
allowed_methodsarray["GET", "POST"]Allowed HTTP methods
allowed_headersarray[]Allowed request headers (beyond simple headers)
expose_headersarray[]Headers exposed to browser JavaScript
max_ageinteger3600Preflight cache time (seconds)
allow_credentialsbooleanfalseAllow credentials (cookies, auth headers)

Origin patterns

Origins can be:

  • Exact match: https://app.example.com
  • Wildcard subdomain: *.example.com (matches sub.example.com)
  • Wildcard: * (only when allow_credentials: false)

Error responses

  • 403 Forbidden — Origin not in allowed list
  • 403 Forbidden — Method not allowed (preflight)
  • 403 Forbidden — Headers not allowed (preflight)

Preflight responses

Returns 204 No Content with:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers
  • Access-Control-Max-Age
  • Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers

ip-restriction

Allows or denies requests based on client IP address or CIDR ranges. Supports both allowlist and denylist modes.

x-barbacane-middlewares:
  - name: ip-restriction
    config:
      allow:
        - 10.0.0.0/8
        - 192.168.1.0/24
      deny:
        - 10.0.0.5
      message: "Access denied from your IP address"
      status: 403

Configuration

PropertyTypeDefaultDescription
allowarray[]Allowed IPs or CIDR ranges (allowlist mode)
denyarray[]Denied IPs or CIDR ranges (denylist mode)
messagestringAccess deniedCustom error message for denied requests
statusinteger403HTTP status code for denied requests

Behavior

  • If deny is configured, IPs in the list are blocked (denylist takes precedence)
  • If allow is configured, only IPs in the list are permitted (allowlist mode)
  • Client IP is extracted from X-Forwarded-For, X-Real-IP, or direct connection
  • Supports both single IPs (10.0.0.1) and CIDR notation (10.0.0.0/8)

Error response

Returns Problem JSON (RFC 7807):

{
  "type": "urn:barbacane:error:ip-restricted",
  "title": "Forbidden",
  "status": 403,
  "detail": "Access denied",
  "client_ip": "203.0.113.50"
}

bot-detection

Blocks requests from known bots and scrapers by matching the User-Agent header against configurable deny patterns. An allow list lets trusted crawlers bypass the deny list.

x-barbacane-middlewares:
  - name: bot-detection
    config:
      deny:
        - scrapy
        - ahrefsbot
        - semrushbot
        - mj12bot
        - dotbot
      allow:
        - Googlebot
        - Bingbot
      block_empty_ua: false
      message: "Automated access is not permitted"
      status: 403

Configuration

PropertyTypeDefaultDescription
denyarray[]User-Agent substrings to block (case-insensitive substring match)
allowarray[]User-Agent substrings that override the deny list (trusted crawlers)
block_empty_uabooleanfalseBlock requests with no User-Agent header
messagestringAccess deniedCustom error message for blocked requests
statusinteger403HTTP status code for blocked requests

Behavior

  • Matching is case-insensitive substring: "bot" matches "AhrefsBot", "DotBot", etc.
  • The allow list takes precedence over deny: a UA matching both allow and deny is allowed through
  • Missing User-Agent is permitted by default; set block_empty_ua: true to block it
  • Both deny and allow are empty by default — the plugin is a no-op unless configured

Error response

Returns Problem JSON (RFC 7807):

{
  "type": "urn:barbacane:error:bot-detected",
  "title": "Forbidden",
  "status": 403,
  "detail": "Access denied",
  "user_agent": "scrapy/2.11"
}

The user_agent field is omitted when the request had no User-Agent header.


request-size-limit

Rejects requests that exceed a configurable body size limit. Checks both Content-Length header and actual body size.

x-barbacane-middlewares:
  - name: request-size-limit
    config:
      max_bytes: 1048576        # 1 MiB
      check_content_length: true

Configuration

PropertyTypeDefaultDescription
max_bytesinteger1048576Maximum allowed request body size in bytes (default: 1 MiB)
check_content_lengthbooleantrueCheck Content-Length header for early rejection

Error response

Returns 413 Payload Too Large with Problem JSON:

{
  "type": "urn:barbacane:error:payload-too-large",
  "title": "Payload Too Large",
  "status": 413,
  "detail": "Request body size 2097152 bytes exceeds maximum allowed size of 1048576 bytes."
}