phase4 HAProxy front config as documentation (T-4.5, RESEARCH-v03 s9; G-104 rate limit template; D-019 notes)
ci / backend (uv, Python 3.12: ruff/mypy/pytest) (push) Successful in 1m18s
ci / frontend (Next.js on pnpm: typecheck/lint/test/build) (push) Successful in 2m11s

This commit is contained in:
2026-10-31 20:44:10 +00:00
parent ce9d1baecf
commit 7598b1707c
+59
View File
@@ -0,0 +1,59 @@
# research.coreci.dev — HAProxy front config for phase 4 (REQ-84, G-104)
#
# DOCUMENTATION + idempotent template (PLAN.md T-4.5, RESEARCH-v03.md §9):
# the host already runs HAProxy 2.8 with the TLS frontend for
# research.coreci.dev. This file is the reviewed shape to fold into that
# front. It is applied to the live host ONLY on owner deploy directive
# (D-019) — never autonomously from a deploy run. The host's live config
# is not readable from the authoring seat, so `timeout client` /
# `defaults` values below are stated as requirements, not as the
# host's current numbers.
# ---- requirements the host's defaults must already satisfy ----------------
# timeout client 3600s # MUST exceed the 15s sse-starlette ping
# # interval (RESEARCH-v03.md §9) or idle SSE
# # streams are cut mid-run.
# keep-alive default ON # keep http-keep-alive; the SSE stream rides it.
# ---- frontend routes -------------------------------------------------------
frontend https-in
acl is_api path_beg /api
acl is_health path /healthz
use_backend backend_api if is_api or is_health
default_backend frontend_next
# G-104 per-IP login rate limit (PLAN.md T-4.5 scope): stick-table on
# /api/auth/*. Threshold below is a STARTING VALUE for the
# security-engineer review, not a measured traffic figure — rate
# before applying. 30 auth requests / 60s / IP.
acl is_auth path_beg /api/auth
stick-table type ip size 100k expire 60s store http_req_rate(60s)
http-request track-sc0 src if is_auth
http-request deny deny_status 429 if is_auth { sc_http_req_rate(0) gt 30 }
# ---- backend: the API container --------------------------------------------
# SSE hazards (RESEARCH-v03.md §9): HAProxy 2.x does NOT buffer response
# bodies in HTTP mode by default, so text/event-stream streams natively.
# The three things that would break it are deliberately absent here:
# - NO `option http-buffer-response` on this backend
# - NO compression (gzip) on this backend — gzip buffers
# text/event-stream; the "classic" silent SSE killer
# - keep the sse-starlette ping (15s) untouched
backend backend_api
option httpchk GET /healthz
default-server inter 5s fall 3 rise 2
server api1 127.0.0.1:8000 check
timeout server 3600s
timeout tunnel 3600s
# ---- backend: the Next.js container ----------------------------------------
backend frontend_next
timeout server 300s
server next1 127.0.0.1:3000 check
# ---- health contract -------------------------------------------------------
# GET /healthz -> 200 {"status":"ok"} (public router, outside /api per
# D-103; the only unauthenticated route — T-4.8).
# The API container must publish on 127.0.0.1:8000 (loopback only: the
# public surface is the TLS front, so the backend is never directly
# reachable from outside the host).