Rate Limiting
Overview
Cloudillo implements rate limiting using GCRA (Generic Cell Rate Algorithm) with hierarchical address grouping and dual-tier limits to protect against abuse, DDoS attacks, and credential stuffing.
Hierarchical Address Levels
Requests are rate-limited at multiple network levels simultaneously. All levels must pass for a request to succeed.
IPv4 Levels
| Level | Mask | Description | Example |
|---|---|---|---|
| Individual | /32 | Single IP address | 192.168.1.100 |
| Network | /24 | Class C network (256 IPs) | 192.168.1.0/24 |
IPv6 Levels
| Level | Mask | Description | Example |
|---|---|---|---|
| Subnet | /64 | Single subnet | 2001:db8:1234:5678::/64 |
| Provider | /48 | ISP allocation | 2001:db8:1234::/48 |
Multi-Level Protection
A single abusive IP can’t overwhelm the system, but neither can a botnet spread across a /24 network. Both individual and network-level limits apply.
Dual-Tier Limits
Each address level has two tiers of limits:
| Tier | Period | Purpose |
|---|---|---|
| Short-term | Per-second | Burst protection |
| Long-term | Per-hour | Sustained abuse protection |
Both tiers must pass.
Default Rate Limits
| Category | IPv4 Individual | IPv4 Network (/24) | IPv6 Subnet (/64) | IPv6 Provider (/48) |
|---|---|---|---|---|
| Auth | 5/s (burst 10), 60/h | 15/s (burst 30), 200/h | 5/s (burst 10), 60/h | 15/s (burst 30), 200/h |
| DAV | 30/s (burst 60), 2000/h | 60/s (burst 120), 5000/h | 30/s (burst 60), 2000/h | 60/s (burst 120), 5000/h |
| Federation | 100/s (burst 200), 1000/h | 500/s (burst 750), 5000/h | 100/s (burst 200), 1000/h | 500/s (burst 750), 5000/h |
| General | 300/s (burst 500), 5000/h | 600/s (burst 1000), 50000/h | 300/s (burst 500), 5000/h | 600/s (burst 1000), 50000/h |
| WebSocket | 100/s (burst 200), 1000/h | 100/s (burst 200), 1000/h | 100/s (burst 200), 1000/h | 100/s (burst 200), 1000/h |
- Auth: Login, registration, password reset
- DAV: Authenticated CardDAV / CalDAV sync
- Federation: Inbox (inter-instance communication)
- General: Profile viewing, refs, normal browsing
- WebSocket: Notification bus, CRDT, RTDB connections (long-lived)
Globally, the limiter tracks up to 100,000 IPs, retaining each entry for one hour after its last request.
Proof-of-Work Protection
CONN (connection request) actions require proof-of-work when violations are detected from an IP address. Violations (failed signature, duplicate pending, rejected CONN) increment a counter tracked at both individual IP and network range levels. The counter decays by 1 every hour.
When PoW is required, the action token must end with N A characters (where N = counter value). For example, counter=2 requires the token to end with AA. The server responds with HTTP 428 (Precondition Required) when PoW is insufficient.
| Parameter | Default | Description |
|---|---|---|
max_counter |
10 | Maximum requirement (10 ‘A’ characters) |
decay_interval_secs |
3600 | Counter decay interval (1 hour) |
max_individual_entries |
50,000 | LRU cache size for individual IPs |
max_network_entries |
10,000 | LRU cache size for network ranges |
Rate-Limited Response
A rate-limited request returns 429 Too Many Requests with two headers and a JSON error body:
| Header | Description |
|---|---|
Retry-After |
Seconds until the request can be retried |
X-RateLimit-Level |
Which address level triggered the limit |
A banned address instead receives 403 Forbidden with code E-RATE-BANNED. PoW failures return 428 Precondition Required with code E-POW-REQUIRED.
Configuration
Rate limits are defined in code (RateLimitConfig::default) and applied process-wide. They are not currently configurable per tenant via the settings system.
See Also
- System Overview - Architecture overview
- Actions API - Action rate limits
- Federation - Federation rate limits