# FastAPI Redis + proxy hardening review notes

Use when reviewing production-readiness changes for FastAPI apps that sit behind nginx/load balancers and use Redis-backed resilience features.

## Proxy/client IP safety

- Do not accept broad proxy trust (`uvicorn --proxy-headers --forwarded-allow-ips '*'`) as an image default unless the deployment makes the app unreachable except from a trusted proxy.
- Prefer one of:
  - explicit trusted proxy CIDRs/IPs from config, then parse `X-Forwarded-For` only when `request.client.host` is trusted;
  - deployment-specific `FORWARDED_ALLOW_IPS` set to the real proxy address/range;
  - no proxy header trust by default.
- Nginx at the edge should replace, not append, client-controlled `X-Forwarded-For` unless a full real-ip trust chain is configured: `proxy_set_header X-Forwarded-For $remote_addr;`.
- Add tests that spoofed `X-Forwarded-For` is ignored from an untrusted peer and accepted only from a trusted proxy peer.
- Apply the same client-IP helper to login/session metadata and IP-based rate-limit keys so audit logs and enforcement agree.

## Redis-backed runtime features

- If Redis is selected by `REDIS_HOST`, readiness should require Redis whenever `REDIS_HOST` is set. If separate feature flags exist, readiness must cover every enabled Redis-backed feature (rate limiter, JTI denylist, provider cooldown, cache).
- Fail-open Redis behavior is acceptable for availability only if documented and observable. Silent fail-open on revocation/rate limiting/cooldown is an operational risk.
- Redis clients used in request paths should have bounded `socket_connect_timeout` and `socket_timeout` to preserve fail-open latency.
- Compose healthchecks must authenticate when Redis has `requirepass`; unauthenticated `redis-cli ping` will report `NOAUTH` and keep the service unhealthy.
- App healthchecks in Docker/Compose: prefer Python stdlib (`urllib.request`) over `curl`/`wget` to avoid depending on additional binaries in a slim image.
- Container healthchecks should use `--retries` to tolerate brief startup jitter, especially when multiple services (DB, Redis, app) start simultaneously.

## Redis sliding-window rate limiters

- Multi-worker rate limiting must be atomic. Separate `ZREMRANGEBYSCORE` / `ZCARD` / `ZADD` / `EXPIRE` awaits are race-prone.
- Use Lua (`EVAL`/registered script) or `WATCH` transaction; Lua is simpler for prune/count/add/TTL.
- Sorted-set members must be unique (UUID/nonce) instead of a timestamp string; otherwise same-member updates can undercount.
- Prefer Redis server `TIME` inside the Lua script for consistent worker-independent timing.
- Unit fakes that mirror the expected behavior are useful, but they do not validate Lua syntax. Add an optional real Redis/fakeredis-Lua integration test when available.
