2 releases
0.1.1 | May 1, 2025 |
---|---|
0.1.0 | May 1, 2025 |
#1337 in HTTP server
247 downloads per month
27KB
417 lines
Axum Rate Limiter
A flexible and powerful rate limiting middleware for Axum web framework that can be configured to limit requests based on various strategies including IP, URL, Headers, Query parameters, and Request body content.
Quick Start
Add the dependency to your Cargo.toml
:
[dependencies]
axum_rate_limiter = "0.1.0"
Basic usage example:
use std::net::SocketAddr;
use std::sync::Arc;
use axum::{
Router,
routing::any,
response::IntoResponse,
};
use axum::body::Body;
use axum::http::{Request, StatusCode};
use axum::middleware::from_fn_with_state;
use axum::response::Response;
use axum_rate_limiter::settings::Settings;
use axum_rate_limiter::limiter::{RateLimiterManager, middleware as rate_limiter_middleware};
// Simple handler that returns "Hello, World!"
async fn handler() -> impl IntoResponse {
"Hello, World!"
}
struct Server {}
impl Server {
async fn run(self) -> Result<(), std::io::Error> {
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
// Use ready-made config or extend your config with RateLimiterSettings
let settings = Settings::new().expect("Failed to create settings");
let limiter_manager = Arc::new(
RateLimiterManager::new(settings.rate_limiter_settings)
.expect("Failed to create rate limiter")
);
let app = Router::new()
.route("/*path", any(handler))
.route("/", any(handler))
.layer(from_fn_with_state(limiter_manager, rate_limiter_middleware));
println!("Server running on http://0.0.0.0:3000");
axum::serve(listener, app.into_make_service_with_connect_info::<SocketAddr>()).await
}
}
#[tokio::main]
async fn main() {
let server = Server {};
if let Err(e) = server.run().await {
eprintln!("Server error: {}", e);
}
}
Features
- Multiple rate limiting strategies
- Redis-based token bucket implementation
- IP whitelisting
- Configurable token bucket parameters
- Support for global and per-value rate limits
- Easy configuration through TOML file
- Flexible configuration path setup via environment variables
Configuration
The rate limiter is configured through a Settings.toml
file. You can specify the path to your configuration file using the RL_SETTINGS_PATH
environment variable. If not specified, the rate limiter will look for the Settings.toml file in the current directory.
# Example of setting custom configuration path
export RL_SETTINGS_PATH=/path/to/your/custom/Settings.toml
Here's a detailed breakdown of the configuration options:
Rate Limiter Base Configuration
[rate_limiter]
redis_addr = "redis:6379" # Redis server address for token bucket storage
ip_whitelist = ["127.0.0.1"] # List of IPs that bypass rate limiting
Rate Limiting Strategies
The rate limiter supports multiple strategies that can be configured simultaneously. Each strategy is defined under [[rate_limiter.limiter]]
section.
Available Strategies
- URL-based Rate Limiting
[[rate_limiter.limiter]]
strategy = "url"
global_bucket = { tokens_count = 10, add_tokens_every = 120 } # Global limit for all URLs
buckets_per_value = [
{ value = "/example", tokens_count = 1, add_tokens_every = 10 }, # Specific limit for /hello
{ value = "/", tokens_count = 5, add_tokens_every = 10 } # Specific limit for /
]
- IP-based Rate Limiting
[[rate_limiter.limiter]]
strategy = "ip"
global_bucket = { tokens_count = 10, add_tokens_every = 120 } # Limit requests per IP
- Header-based Rate Limiting
[[rate_limiter.limiter]]
strategy = "header"
global_bucket = { tokens_count = 3, add_tokens_every = 120 }
buckets_per_value = [
{ value = "X-Telegram-User-Token", tokens_count = 1, add_tokens_every = 100 },
]
- Query Parameter Rate Limiting
[[rate_limiter.limiter]]
strategy = "query"
buckets_per_value = [
{ value = "user_id", tokens_count = 1, add_tokens_every = 30 },
]
- Request Body Rate Limiting
[[rate_limiter.limiter]]
strategy = "body"
buckets_per_value = [
{ value = "user_id", tokens_count = 1, add_tokens_every = 30 },
]
Configuration Parameters Explained
strategy
: The type of rate limiting to apply (url
,ip
,header
,query
, orbody
)global_bucket
: Global rate limit settings that apply to all values for the strategytokens_count
: Number of tokens (requests) allowedadd_tokens_every
: Time in seconds after which tokens are replenished
buckets_per_value
: Specific rate limits for individual valuesvalue
: The specific value to apply the limit to (e.g., URL path, header name, query parameter)tokens_count
: Number of tokens (requests) allowed for this specific valueadd_tokens_every
: Time in seconds after which tokens are replenished for this value
Usage Examples
Example 1: Basic URL Rate Limiting
[[rate_limiter.limiter]]
strategy = "url"
buckets_per_value = [
{ value = "/api/users", tokens_count = 5, add_tokens_every = 60 }, # 5 requests per minute
]
Example 2: Combined IP and Header Rate Limiting
[[rate_limiter.limiter]]
strategy = "ip"
global_bucket = { tokens_count = 100, add_tokens_every = 3600 } # 100 requests per hour per IP
[[rate_limiter.limiter]]
strategy = "header"
buckets_per_value = [
{ value = "API-Key", tokens_count = 1000, add_tokens_every = 3600 }, # 1000 requests per hour per API key
]
Error Responses
When rate limits are exceeded, the service will return:
- HTTP Status Code: 429 (Too Many Requests)
- A message indicating the rate limit has been exceeded
Notes
- The rate limiter uses a token bucket algorithm implemented with Redis
- Whitelisted IPs bypass all rate limiting rules
- Each strategy can have both global and specific limits (Except
query
andbody
) - Token buckets are replenished gradually over time
- Configuration changes require service restart to take effect
Dependencies
~13–23MB
~342K SLoC