1. Start a local demo
Install Docker with Compose and start the Docker engine. No Go installation or repository checkout is needed. Pull the published image:
docker pull hiteshs0lanki/distributed-rate-limiter:latestIn an empty directory, save this as compose.yaml. It starts the gateway and the demo backend included in the same image. Only the gateway publishes a host port.
name: rate-limiter-demo
services:
gateway:
image: hiteshs0lanki/distributed-rate-limiter:latest
ports:
- "127.0.0.1:8088:8080"
environment:
RATE_LIMIT_STORAGE: ram
RATE_LIMIT_UPSTREAM: http://backend:8080
read_only: true
cap_drop: [ALL]
security_opt: [no-new-privileges:true]
depends_on:
backend:
condition: service_healthy
backend:
image: hiteshs0lanki/distributed-rate-limiter:latest
entrypoint: ["/demo-backend"]
command: []
healthcheck:
test: [CMD, /ratelimitd, -healthcheck, "http://127.0.0.1:8080/healthz"]
interval: 5s
timeout: 3s
retries: 5docker compose up -d --waitThe gateway is available at http://localhost:8088. Its bundled configuration allows three requests per client IP in each fixed 10-second window. RAM mode keeps counters in one gateway process.
2. Verify forwarding and limits
Check readiness, then send four requests in quick succession:
curl -i http://localhost:8088/readyz
curl -i http://localhost:8088/orders
curl -i http://localhost:8088/orders
curl -i http://localhost:8088/orders
curl -i http://localhost:8088/ordersReadiness returns 200. Within one window, the first three order requests return 200 and the fourth returns 429 with a Retry-After header. If the requests cross a window boundary, the allowance resets. Wait for the next window to try again.
Readiness checks do not consume quota. The demo backend echoes forwarded requests, so you can also try a POST after the quota resets:
curl -i -X POST 'http://localhost:8088/orders?source=demo' -d 'hello'3. Connect your own backend
For a backend on an existing Docker network, run the gateway on that network. Replace your-app-network and your-backend:3000 with your network and service address:
docker run -d --name rate-limiter \
--network your-app-network \
-p 127.0.0.1:8089:8080 \
--read-only --cap-drop ALL \
--security-opt no-new-privileges:true \
-e RATE_LIMIT_UPSTREAM=http://your-backend:3000 \
hiteshs0lanki/distributed-rate-limiter:latestSend API traffic to http://localhost:8089. On Docker Desktop, a backend running on your host can use http://host.docker.internal:3000 as the upstream. Inside a container, localhost refers to that container.
To customize routes, limits, windows, or identity policies, mount your complete version-1 proxy configuration with -v "$PWD/proxy.json:/etc/ratelimit/proxy.json:ro". Restart the container after changing the file. The architecture page has a configuration editor for exploring policies.
4. Share quotas with Redis
Use Redis when multiple gateways need one shared allowance. Save the following beside compose.yaml as compose.redis.yaml. Redis stays on the private Compose network.
services:
gateway:
environment:
RATE_LIMIT_STORAGE: redis
REDIS_URL: redis://redis:6379/0
depends_on:
redis:
condition: service_healthy
redis:
image: redis:7.4.7-alpine
command: [redis-server, --appendonly, "yes", --maxmemory, 128mb, --maxmemory-policy, noeviction]
volumes:
- redis-data:/data
healthcheck:
test: [CMD, redis-cli, ping]
interval: 2s
timeout: 2s
retries: 15
volumes:
redis-data:docker compose down
docker compose -f compose.yaml -f compose.redis.yaml up -d --waitReplicas must use the same namespace and policy settings, including revisions. Configure RATE_LIMIT_NAMESPACE to separate deployments. Redis counters survive gateway restarts until expiry; if Redis becomes unavailable, the gateway returns 503 and does not forward requests.
5. Inspect, update, and stop
docker compose logs -f gateway
# Pull the latest image and recreate the services
docker compose pull
docker compose up -d --wait
# Stop and remove the demo containers
docker compose downFor Redis mode, include -f compose.yaml -f compose.redis.yaml in each Compose command. Stopping the stack preserves the Redis volume; adding -v deletes it and resets stored state. Remove the standalone gateway with docker rm -f rate-limiter.
| Response | Meaning |
|---|---|
| /healthz | Gateway process is alive. |
| /readyz | Gateway is ready; includes Redis checks in Redis mode, but does not check the upstream. |
| 429 | Request allowance exhausted. Retry after the indicated delay. |
| 503 | Rate-limit storage or key capacity unavailable. |
| 502 / 504 | Upstream unreachable or timed out. Check its address and network. |
The examples bind to loopback for local use. For a public deployment, terminate TLS at your ingress and keep the backend private so clients cannot bypass the gateway. The latest tag can change; pin a tested image digest for reproducible deployments.