Use --env-file deploy/web.pre.env whenever you invoke this Compose file. Compose
uses that option for ${CLOUDFLARE_TURNSTILE_SITE_KEY} interpolation in the
viewer web build arguments; the web service's env_file alone does not provide
values for build interpolation.
For example, from the repository root:
docker compose --env-file deploy/web.pre.env -f deploy/httpsms-pre-compose.yml build viewer-web
docker compose --env-file deploy/web.pre.env -f deploy/httpsms-pre-compose.yml up -dCLOUDFLARE_TURNSTILE_SITE_KEY is a public widget key. Search is disabled by
default through VIEWER_SEARCH_ENABLED=false. Keep it false unless
deploy/viewer.pre.env contains the exact Nginx source address in
TRUSTED_PROXIES and the forwarded client IP chain has been verified. Only
then set VIEWER_SEARCH_ENABLED=true and rebuild viewer-web. A missing site
key also keeps search hidden. Keep BFF credentials in deploy/viewer.pre.env;
they are loaded at container runtime and are never build arguments.
The BFF enforces Redis-backed limits across replicas: login is limited to 120
requests per observed client IP per 15 minutes, callback to 120 per observed IP per 15
minutes, session/thread/message reads to 60 per session per minute, search to 20
per session per minute, and logout to 10 per session per minute. Each route also
has an independent site-wide ceiling (1200 login/callback requests per 15
minutes; 6000 session/thread/message reads, 2000 searches, or 1000 logout
requests per minute) to bound temporary rate-key storage and total request
volume. If Redis is
unavailable, these requests fail closed with a generic 503. The BFF derives
client IP through Fiber's trusted-proxy allowlist; it does not read forwarded IP
headers directly. web/nginx.conf replaces the incoming forwarding headers
with $remote_addr, so the allowlist must contain only the exact source address
of the Nginx container on its path to viewer-bff. With an empty allowlist,
Fiber sees the Nginx container address for every anonymous login/callback; the
120 per-IP limit caps each route at 120 requests across all users per 15
minutes. The separate 1200 request site-wide ceiling still applies. This mode
remains header-spoof-safe; do not trust a broad or operator-controlled client
header to work around that aggregation.