Rate limiting

Ferron implements token bucket-based rate limiting with the rate_limit directive. This helps reduce brute-force login attempts and API abuse. When a client exceeds the configured rate, the server returns a 429 Too Many Requests response with a Retry-After header.

Protect login endpoints⁠#

Apply stricter limits to authentication paths than to the rest of the site:

example.com {
    root /var/www/html

    # General traffic limit for the site.
    rate_limit {
        rate 50
        burst 100
        key remote_address
    }

    # Tighter limits for login endpoints.
    location /login {
        rate_limit {
            rate 5
            burst 10
            key remote_address
        }
    }

    location /api/auth {
        rate_limit {
            rate 5
            burst 10
            key remote_address
        }
    }
}
Note
  • Rate limiting uses a token bucket algorithm: capacity = rate + burst tokens, refilled at rate tokens per second.
  • Ferron stores in-memory rate limit buckets in memory. They do not survive configuration reloads. Redis-backed buckets survive reloads.
Info

For distributed rate limiting across Ferron instances, configure a rate_limit_backend block with type redis. See rate limiting configuration for details. Redis failures allow by default (fail_open true), use fail_open false for high-security endpoints like login.

Important

If Ferron is behind another proxy/load balancer, make sure the client IP is correctly resolved. See HTTP host directives for client_ip_from_header configuration.

Protect APIs with tiered limits⁠#

Use host-level and location-level limits together:

api.example.com {
    location / {
        proxy http://localhost:3000

        # Default API limit.
        rate_limit {
            rate 100
            burst 200
            key remote_address
        }
    }

    # Heavier endpoints can have stricter caps.
    location /v1/search {
        rate_limit {
            rate 20
            burst 40
            key remote_address
        }
    }

    location /v1/login {
        rate_limit {
            rate 5
            burst 10
            key remote_address
        }
    }
}
Tip

Start with permissive values. Tighten them after you observe production traffic patterns. Keep login and token endpoints on stricter limits than read-only API endpoints.

API key rate limiting⁠#

You can also key rate limits off request headers (for example, API keys):

api.example.com {
    proxy http://localhost:3000

    rate_limit {
        rate 50
        burst 100
        key request.header.X-Api-Key
    }
}

Each unique API key gets its own token bucket, independent of the client IP.

Throttling⁠#

To enable throttling for rate-limited requests, use the throttle subdirective:

api.example.com {
    proxy http://localhost:3000
    rate_limit {
        rate 50
        burst 100
        key request.header.X-Api-Key
        throttle
    }
}

JSON rate limit responses⁠#

By default, when a client exceeds the rate limit, Ferron responds with an HTTP 429 Too Many Requests status code and includes an HTML-format message. You can customize this response to return a JSON object instead using json_errors directive:

api.example.com {
    proxy http://localhost:3000
    rate_limit {
        rate 50
        burst 100
        key remote_address
    }
    json_errors
}