Files
kjvstudy.org/scripts/search_api.py
kennethreitz 2ab3dfa142 Add static site generation with nginx + hardened FastAPI sidecar
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>
2026-01-31 21:59:34 -05:00

44 lines
1.3 KiB
Python

#!/usr/bin/env python3
"""FastAPI sidecar for kjvstudy.org static site deployment.
Handles routes that can't be pre-rendered as static HTML:
- /search and /api/search (dynamic query)
- /api/* (JSON API endpoints)
- /*/pdf (on-demand PDF generation)
- /random-verse (server-side redirect fallback)
- /verse-of-the-day (redirect to today's date)
- /og/* (dynamic OG images)
Runs on port 8001, proxied by nginx.
Uses gunicorn with uvicorn workers for resilience.
"""
import os
import subprocess
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(PROJECT_ROOT))
from kjvstudy_org.server import app # noqa: E402, F401
if __name__ == "__main__":
port = int(os.getenv("SIDECAR_PORT", "8001"))
workers = int(os.getenv("SIDECAR_WORKERS", "1"))
subprocess.run([
sys.executable, "-m", "gunicorn",
"kjvstudy_org.server:app",
"--worker-class", "uvicorn.workers.UvicornWorker",
"--bind", f"0.0.0.0:{port}",
"--workers", str(workers),
"--max-requests", "1000",
"--max-requests-jitter", "200",
"--timeout", "60",
"--graceful-timeout", "10",
"--forwarded-allow-ips", "*",
"--log-level", "warning",
"--access-logfile", "-",
])