Replaces gunicorn + uvicorn with granian across all entry points (Dockerfile,
docker-compose, main.py, sidecar script). Static files are now served directly
from granian's Rust layer, bypassing Python entirely for /static routes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pre-render ~1,277 high-traffic HTML pages (homepage, books, chapters)
at build time and serve them directly via nginx. All other routes
(verses, search, API, PDFs, Strong's) fall through to a FastAPI
sidecar. If the sidecar crashes, nginx continues serving static
pages and health checks.
Also harden the FastAPI app against the memory/crash issues:
- Switch from bare uvicorn to gunicorn with uvicorn workers
- Add --max-requests worker recycling to prevent memory leaks
- Add --timeout to kill hung workers
- Add per-IP rate limiting middleware (10 req/s, burst of 50)
- Add request timeout middleware (30s max per request)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>