Last 12 weeks · 1 commit
2 of 6 standards met
Hi there. LOVE the module. I installed it the other day, because I've been under attack by AI scrapers. I've served 92 Million requests to AI in the last week. Over 600GB of AI scraping. I implemented a rate-limiter, but I'm getting ABSOLUTELY SPAMMED TO DEATH by log entries. It's not a problem now, but it will be, because the AI apocalypse is not going away. One __second__ of logging, during the assault, __AFTER__ limiting incoming request traffic to 2MBIT/sec. I don't see how to disable logging. I see one way to enable logging (), but it __isn't__ enabled. Relevant bits in Caddyfile; How do I disable logging for rate_limit? Also, is there a means to use ipv4_prefix as key? I couldn't get it to work, but it would be more useful than any of the other keys, in my use case.
Hi, It would be nice to be able to limit the number of requests that a client can make not just in a time range, but concurrently. For example, if a client has reached a maximum number of allowed simultaneous requests, then another one will be rejected with 429 until at least another one finishes, after which they can try again. Thanks
Features Concurrency Limiting: Added a new configuration option to limit in-flight requests per key. Mutually Exclusive Zones: A rate limit zone must define either window/events or max_concurrent, but not both. Design Decisions & Architecture Atomic Counters (): Implemented using fast, lock-free atomic.Int64 counters Deferred Rollback (toRelease): When a request matches multiple zones and passes a concurrency zone but gets rejected by a subsequent windowed zone, a defer block ensures the concurrency limit is released. Garbage Collection (Sweep): Concurrency limiters track their lastAccess time. The background sweep() goroutine safely cleans them up if they are idle for a minute and have 0 active requests. Config Reload: The getOrInsert method now explicitly checks the RateLimiter underlying type. If user hot-reloads Caddy to change a zone from a window limit to a concurrency limit, it cleanly recreates the limiter. Permissiveness Sorting Optimization: max_concurrent is mathematically mapped to an equivalent “events per second” rate. This allows the handler to evaluate the strictest limiters first, saving CPU cycles on requests that are set to fail anyway. Disclosure: PR assisted by AI (Gemini), signed-off by me.
With #85 ratelimit exposes metrics until a live reload happens! After that, ratelimit metrics aren't exposed anymore! Caddy supports live config reloads: when the Caddyfile changes (e.g. because a Kubernetes ConfigMap mount is updated after a helm upgrade), Caddy calls Provision() on all handlers again without restarting the process. On each reload, Caddy internally creates a new Prometheus registry (Registry-2). The admin /metrics endpoint switches to serve this new registry. All modules are expected to re-register their metrics against it. caddy-ratelimit does this in registerMetrics(): What happens next: globalMetrics still points to the collector objects registered with Registry-1 When a request is rate-limited, globalMetrics.declinedRequests.Inc() increments counters in Registry-1 /metrics serves Registry-2 — which has no increments Result: all caddy_rate_limit_* metrics appear stuck at 0 after any config reload Fix: globalMetrics must be updated on every Provision() call, not only when it is nil: This is safe because Provision() is called exactly once per reload and the newly created collector objects are already registered with the new registry at that point.
Fixes #100: metrics stop updating after a config reload (e.g. a ConfigMap remount after ). What's going on Caddy makes a fresh prometheus registry on every reload and points at the new one. only set the singleton while it was nil, so after a reload it kept pointing at the old registry's collectors. Increments went there while served the new (empty) one — so the series read 0. The fix Register collectors against the registry passed to each , and store them in an so the active collectors always match the registry is serving. Keep the one useful thing the nil check did — avoiding double-registration when multiple handlers share a registry — by reusing instead of dropping the new collectors. The atomic pointer also closes the data race raised in the issue: reads the singleton from request goroutines while a reload writes it, and the new config is provisioned before the old one stops, so live requests overlap the write. Tests — post-reload increments land in the new registry (fails on the old code). — concurrent reloads vs. request reads, clean under . passes.
Repository: mholt/caddy-ratelimit. Description: HTTP rate limiting module for Caddy 2 Stars: 485, Forks: 35. Primary language: Go. Languages: Go (100%). License: Apache-2.0. Topics: caddy, caddy-module, rate-limiting. Open PRs: 1, open issues: 12. Last activity: 2mo ago. Community health: 42%. Top contributors: mholt, tgeoghegan, dependabot[bot], steffenbusch, IceCodeNew, chalabi2, mohammed90, inahga, divergentdave, popcorn and others.