Add `ingester.api.root_path` so the HTTP control plane (dashboard + API)
can be reverse-proxied behind a sub-path (e.g. /ingester/) on a shared
origin, instead of needing nginx sub_filter URL-rewriting.
- APIConfig.root_path: normalized ('', or single leading slash, no trailing
slash) via a field_validator; validate_assignment so CLI overrides
normalize the same way as config-file values.
- Forwarded to FastAPI(root_path=) and uvicorn.Config(root_path=) so
OpenAPI/docs links are prefix-aware.
- Dashboard route injects a <base href> matching root_path; all dashboard
fetches are now base-relative, so they resolve under the prefix while
staying identical at the root.
- `serve --root-path` CLI flag.
- Docs: "Behind a reverse proxy" section with an nginx example.
Closes #431
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
26 lines
1.1 KiB
Python
26 lines
1.1 KiB
Python
from pathlib import Path
|
|
|
|
from fastapi import APIRouter, Request
|
|
from fastapi.responses import HTMLResponse
|
|
|
|
router = APIRouter(tags=["dashboard"])
|
|
|
|
_INDEX_HTML_PATH = Path(__file__).resolve().parent.parent / "static" / "index.html"
|
|
_INDEX_HTML = _INDEX_HTML_PATH.read_text(encoding="utf-8")
|
|
|
|
|
|
@router.get("/", include_in_schema=False)
|
|
async def dashboard(request: Request) -> HTMLResponse:
|
|
"""Serve the operator dashboard. Static page that polls /health, /sources,
|
|
/stats and /jobs from the browser. Auth happens via the bearer header the
|
|
JS attaches to its fetches — the dashboard route itself is unauthenticated
|
|
so an operator can open it in a browser and paste the token on demand.
|
|
|
|
A ``<base href>`` matching the server's ``root_path`` is injected so the
|
|
page's relative fetches resolve correctly whether the control plane is
|
|
served at the root or reverse-proxied under a sub-path (e.g. ``/ingester/``).
|
|
"""
|
|
root_path = request.scope.get("root_path", "")
|
|
base_href = f"{root_path}/" if root_path else "/"
|
|
html = _INDEX_HTML.replace("<head>", f'<head>\n <base href="{base_href}" />', 1)
|
|
return HTMLResponse(html)
|