#rate-limiting #actix-web #redis #actix-web-middleware #rate #in-memory-store #concurrency #require #sliding-window

actix-web-ratelimit

A simple and highly customizable rate limiter for actix-web 4

2 releases

Uses new Rust 2024

0.1.1 Jun 20, 2025
0.1.0 Jun 18, 2025

#35 in Security

Download history 275/week @ 2025-06-18 26/week @ 2025-06-25 6/week @ 2025-07-02

307 downloads per month

MIT license

39KB
288 lines

actix-web-ratelimit

A simple and highly customizable rate limiting middleware for actix-web 4.

Crates.io Documentation License: MIT CI

中文文档

Features

  • actix-web 4 Compatible: Built specifically for actix-web 4
  • Simple & Easy to Use: Minimal configuration required
  • Expandable Store: easy to create your own store, In-Memory store and Redis store have been provided
  • High Performance: Efficient sliding window algorithm
  • Customizable: Custom client identification and rate limit exceeded handlers
  • Thread Safe: Concurrent request handling with DashMap

Quick Start

Add this to your Cargo.toml:

[dependencies]
actix-web-ratelimit = "0.1"

# Or, for Redis support
actix-web-ratelimit = { version = "0.1", features = ["redis"] }

Usage

Basic Usage with In-Memory Store

    // Configure rate limiting: allow 3 requests per 10-second window
    let config = RateLimitConfig::default().max_requests(3).window_secs(10);
    // Create in-memory store for tracking request timestamps
    let store = Arc::new(MemoryStore::new());

    HttpServer::new(move || {
        App::new()
            // create and register the rate limit middleware
            .wrap(RateLimit::new(config.clone(), store.clone()))
            .route("/", web::get().to(index))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await

Advanced Configuration

    let store = Arc::new(MemoryStore::new());
    let config = RateLimitConfig::default()
        .max_requests(3)
        .window_secs(10)
        // Extract client identifier from req. It is IP (realip_remote_addr) by default.
        .id(|req| {
            req.headers()
                .get("X-Client-Id")
                .and_then(|h| h.to_str().ok())
                .unwrap_or("anonymous")
                .to_string()
        })
        // Custom handler for rate limit exceeded. It returns a 429 response by default.
        .exceeded(|id, config, _req| {
            HttpResponse::TooManyRequests().body(format!(
                "429 caused: client-id: {}, limit: {}req/{:?}",
                id, config.max_requests, config.window_secs
            ))
        });

    HttpServer::new(move || {
        App::new()
            .wrap(RateLimit::new(config.clone(), store.clone()))
            .route("/", web::get().to(index))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await

Redis Store

first set feature redis enable:

actix-web-ratelimit = { version = "0.1", features = [ "redis" ] }

then you can use it:

    let store = Arc::new(
        RedisStore::new("redis://127.0.0.1/0")
            .expect("Failed to connect to Redis")
            // Custom prefix for Redis keys
            .with_prefix("myapp:ratelimit:"),
    );
    let config = RateLimitConfig::default().max_requests(3).window_secs(10);

    HttpServer::new(move || {
        App::new()
            .wrap(RateLimit::new(config.clone(), store.clone()))
            .route("/", web::get().to(index))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await

Configuration Options

RateLimitConfig

Method Description Default
max_requests(usize) Maximum requests per window 10
window_secs(u64) Time window in seconds 100
id(fn) Client identification function IP address
exceeded(fn) Rate limit exceeded handler 429 response

Storage Backends

MemoryStore

  • Pros: Fast, no external dependencies
  • Cons: Not distributed, data lost on restart
  • Use case: Single instance applications

RedisStore (requires redis feature)

  • Pros: Distributed, persistent, scalable
  • Cons: Requires Redis server
  • Use case: Multi-instance applications

Algorithm

This middleware uses a sliding window algorithm:

  1. Extract client identifier from request
  2. Retrieve stored request timestamps for the client
  3. Remove expired timestamps outside the time window
  4. Check if remaining request count exceeds the limit
  5. If not exceeded, record new timestamp and allow request
  6. If exceeded, call the rate limit handler

Examples

Run the example:

cargo run --example simple

Then test the rate limiting:

# This should work
curl http://localhost:8080/

# Exceed rate limit by making many requests
for i in {1..5}; do echo "$(curl -s http://localhost:8080)\r"; done

Features

  • redis: Enables Redis storage backend support

License

This project is licensed under the MIT License.

Dependencies

~17–28MB
~485K SLoC