Rate Limiting
Sockudo includes a built-in rate limiter that protects both the HTTP API and WebSocket connection endpoints. Rate limits use a sliding window algorithm and support multiple backends.
How It Works
The rate limiter tracks requests per client IP using a sliding time window. When a client exceeds the limit, further requests receive a 429 Too Many Requests response until the window resets.
Two independent rate limits are enforced:
| Limit | Protects | Default |
|---|---|---|
| API rate limit | HTTP API endpoints (/apps/{appId}/events, etc.) | 100 requests / 60 seconds |
| WebSocket rate limit | New WebSocket connections (/app/{appKey}) | 20 connections / 60 seconds |
Configuration
{
"rate_limiter": {
"enabled": true,
"driver": "memory",
"api_rate_limit": {
"max_requests": 100,
"window_seconds": 60,
"trust_hops": 0
},
"websocket_rate_limit": {
"max_requests": 20,
"window_seconds": 60,
"trust_hops": 0
}
}
}
API Rate Limit
| Setting | Env Var | Default | Description |
|---|---|---|---|
max_requests | RATE_LIMITER_API_MAX_REQUESTS | 100 | Max requests per window |
window_seconds | RATE_LIMITER_API_WINDOW_SECONDS | 60 | Window duration in seconds |
trust_hops | RATE_LIMITER_API_TRUST_HOPS | 0 | Trusted proxy hops (for X-Forwarded-For) |
WebSocket Rate Limit
| Setting | Env Var | Default | Description |
|---|---|---|---|
max_requests | RATE_LIMITER_WS_MAX_REQUESTS | 20 | Max connections per window |
window_seconds | RATE_LIMITER_WS_WINDOW_SECONDS | 60 | Window duration in seconds |
Enable / Disable
RATE_LIMITER_ENABLED=true
Drivers
The rate limiter backend is configured separately from the cache driver:
| Driver | Shared Across Nodes | External Dependency |
|---|---|---|
memory | No | None |
redis | Yes | Redis 6+ |
redis-cluster | Yes | Redis Cluster 6+ |
none | N/A | None |
RATE_LIMITER_DRIVER=memory
Memory Backend
Uses in-memory DashMap with a background cleanup task that runs every 10 seconds to remove expired entries. Fast but node-local - each Sockudo instance tracks limits independently.
Redis Backend
Uses Redis sorted sets (ZSET) for a true sliding window. The algorithm:
- Remove entries older than the window:
ZREMRANGEBYSCORE - Count current entries:
ZCARD - If under the limit, add the current timestamp:
ZADD - Set key expiry:
EXPIRE
This provides cluster-wide rate limiting - all Sockudo nodes share the same counters.
{
"rate_limiter": {
"driver": "redis",
"redis": {
"prefix": "sockudo_rl:",
"url_override": null,
"cluster_mode": false
}
}
}
| Setting | Env Var | Default | Description |
|---|---|---|---|
prefix | RATE_LIMITER_REDIS_PREFIX | sockudo_rl: | Redis key prefix |
url_override | — | null | Override Redis URL |
cluster_mode | — | false | Use cluster-aware connections |
Proxy Trust (trust_hops)
When Sockudo runs behind a reverse proxy or load balancer, client IPs appear as the proxy's IP. The trust_hops setting controls how many X-Forwarded-For hops to trust:
| Value | Behavior |
|---|---|
0 | Use the direct connection IP (default, safest) |
1 | Trust one proxy hop (e.g., single load balancer) |
2 | Trust two hops (e.g., CDN + load balancer) |
# Behind one load balancer
RATE_LIMITER_API_TRUST_HOPS=1
trust_hops too high allows clients to spoof their IP by adding fake X-Forwarded-For headers. Only trust the exact number of proxies in your infrastructure.Response Headers
When rate limiting is active, responses include standard rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1707744060
When the limit is exceeded:
HTTP/1.1 429 Too Many Requests
Retry-After: 45
Choosing a Driver
| Scenario | Recommended Driver |
|---|---|
| Single-node, development | memory |
| Multi-node production | redis |
| Rate limiting not needed | none |
For multi-node deployments, the memory driver means each node enforces limits independently. A client could hit Node A 100 times and Node B 100 times, effectively doubling the limit. Use redis for consistent cluster-wide enforcement.