Production-ready rate limiting and DDoS protection for Python web frameworks
Project description
drogue -- Rate Limiting and DDoS Protection for Python
Drop-in replacement for slowapi with DDoS detection, WebSocket support, and 9x faster trusted-user paths.
Author: Zlynv
Why drogue?
slowapi requires request: Request in every endpoint, does not support WebSocket, and has no DDoS detection.
drogue fixes all three:
# slowapi -- polluted signature, no WebSocket, no DDoS detection
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data(request: Request): # forced parameter
return {"data": "value"}
# drogue -- clean signature, WebSocket support, DDoS detection
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data(): # clean
return {"data": "value"}
What drogue adds that slowapi does not have:
- Clean signatures -- no
request: Requestneeded - WebSocket rate limiting --
@limiter.limit_ws("100/minute") - DDoS detection -- Z-score anomaly detection plus streaming Sentinel Model
- Early warning -- probe pattern detection 30-120 seconds before attacks
- Trust caching -- 9x throughput for verified users (5 microseconds vs 43 microseconds)
- Defense randomization -- attackers cannot learn your thresholds
- Memory efficient -- 10MB in-process replaces 80MB Redis
Install
pip install drogue
# With framework support
pip install drogue[fastapi] # FastAPI + Starlette
pip install drogue[django] # Django
pip install drogue[flask] # Flask
pip install drogue[drf] # Django REST Framework
pip install drogue[redis] # Redis backend
pip install drogue[all] # Everything
Quick Start
from fastapi import FastAPI
from drogue.adapters.fastapi import DrogueLimiter
app = FastAPI()
limiter = DrogueLimiter(app, default_limits=["100/minute"])
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data():
return {"data": "value"}
@app.get("/api/heavy")
@limiter.limit("3/minute") # expensive endpoints get lower limits
async def heavy_operation():
return {"result": "computed"}
That is it. No request parameter. No middleware setup. Works with Flask and Django too -- see docs/getting-started.
Features
Rate Limiting -- Token Bucket (burst-friendly), Sliding Window (most accurate), Fixed Window (simplest), cost-aware limits, blocking mode
Storage -- In-memory (5 microseconds), Redis (distributed), Count-Min Sketch (10MB for 1M keys)
Frameworks -- FastAPI (pure ASGI middleware), Flask (decorator plus hook), Django (decorator plus middleware)
Protection -- DDoS detection (Z-score plus streaming), probe detection (early warning), progressive auto-ban (5 levels), circuit breaker, CIDR filtering, adaptive limits, shadow mode, trust caching, defense randomization, honeypots
Observability -- Prometheus metrics, OpenTelemetry tracing, structured logging
Performance
| Metric | drogue | Context |
|---|---|---|
| Trusted user | ~5 microseconds | Faster than a function call |
| Standard user | ~43 microseconds | 7-23x faster than Redis round-trip |
| Suspicious user | ~200 microseconds | Full pipeline, still under 1ms |
| Throughput | 741K req/s | Token Bucket, single worker |
| Memory per key | 150 bytes | vs 800 bytes in Redis |
| Count-Min Sketch | 10MB | Replaces 800MB Redis for 1M keys |
Measured on Intel i7-12700K, Python 3.12, asyncio single-worker, median of 10,000 requests.
Migrate from slowapi
Before:
from slowapi import Limiter
from slowapi.util import get_remote_address
from starlette.requests import Request
limiter = Limiter(key_func=get_remote_address)
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data(request: Request):
return {"data": "value"}
After:
from drogue.adapters.fastapi import DrogueLimiter
limiter = DrogueLimiter(app)
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data():
return {"data": "value"}
Migration checklist:
- Replace
from slowapi import Limiterwithfrom drogue.adapters.fastapi import DrogueLimiter - Replace
Limiter(key_func=get_remote_address)withDrogueLimiter(app) - Remove
request: Requestfrom decorated endpoints - Rate limit headers work the same (X-RateLimit-Limit/Remaining/Reset)
- Redis config: same URL format, add
storage_backend="redis"to config
Competitive Matrix
| Feature | drogue | slowapi | Next closest |
|---|---|---|---|
| Cross-framework | FastAPI + Flask + Django | FastAPI only | Django only |
| Clean signatures | Yes | No | No (rateon only) |
| WebSocket | Yes | No | No |
| DDoS detection | Yes (Z-score + streaming) | No | No |
| Trust caching (9x speedup) | Yes | No | No |
| Count-Min Sketch | Yes (10MB for 1M keys) | No | No |
| Geo-blocking | No | No | Yes (fastapi-guard) |
Known Limitations
- Ban state is in-memory only by default. Redis persistence planned for v0.3.
- Trust cache is per-process. Multi-worker setups need separate trust state per worker.
- Flask headers for dict-returning views do not inject automatically.
Security
If you discover a security vulnerability, please open a GitHub issue with the [security] tag. We will respond within 48 hours.
Roadmap
- v0.2 -- Redis-backed ban state, WebSocket support for Django and Flask
- v0.3 -- Trust cache cross-process sync, advanced Sentinel features
- v1.0 -- Production-ready, full documentation site
Development
git clone https://github.com/Zlynv/drogue.git
cd drogue
pip install -e ".[dev]"
# Run tests
pytest
# Run linting
ruff check src/drogue/
# Run integration tests
cd _integration_test && pip install -r requirements.txt && pytest
License
MIT License. See LICENSE for details.
Author
Created by Zlynv.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file drogue-0.1.0.tar.gz.
File metadata
- Download URL: drogue-0.1.0.tar.gz
- Upload date:
- Size: 93.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e84e23cdd9903c09850ca028f6e0cb977915cf5ee7428022776a5c7866e764d3
|
|
| MD5 |
c33ed5729dfd59aeccc18d9022431663
|
|
| BLAKE2b-256 |
ea427bb998c56411bc81bd483957bd1a52ac8651a6ab72f3d67f447a04bf6df6
|
File details
Details for the file drogue-0.1.0-py3-none-any.whl.
File metadata
- Download URL: drogue-0.1.0-py3-none-any.whl
- Upload date:
- Size: 71.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e76dc7083d971c3dcf2b5cef6fed266d7c3cb22f5d886ddb84a2dc00084b341d
|
|
| MD5 |
163ba416301139806833e53fa901bfe6
|
|
| BLAKE2b-256 |
6d152b7e44b37c5a41a23c07ff7cadf97730111bb886e2743e07cc2e09ae1b58
|