62 lines
3.3 KiB
Plaintext
62 lines
3.3 KiB
Plaintext
# ─────────────────────────────────────────────────────────────────────────────
|
|||
|
|
# sitomat — SINGLE-DOMAIN reverse proxy (Opsi A).
|
||
|
|
#
|
||
|
|
# ONE public origin serves BOTH the web UI and the API; routing is by PATH. A
|
||
|
|
# small, explicit set of API prefixes goes to the API, everything else to the
|
||
|
|
# web — which is what lets the deployment expose a single port / domain.
|
||
|
|
#
|
||
|
|
# WHY ONLY THESE PREFIXES: most API routes (`/datasets`, `/submissions`,
|
||
|
|
# `/services`, `/standards`, …) COLLIDE with web pages of the same name. They do
|
||
|
|
# not need a public path because the web calls them SERVER-SIDE (Eden →
|
||
|
|
# `http://api:13000`) over the internal network. Only endpoints the BROWSER — or
|
||
|
|
# an external M2M client — hits directly are routed here:
|
||
|
|
#
|
||
|
|
# /api/auth/* better-auth (login/session) ← NEXT_PUBLIC_API_URL
|
||
|
|
# /api/v1/* documented read API (F09-A)
|
||
|
|
# /public/* open-data downloads (F07)
|
||
|
|
# /ingest/v1/* push ingest (F09-B)
|
||
|
|
# /docs swagger
|
||
|
|
# /health health check
|
||
|
|
# /datasets/<id>/versions/<v>/download browser download (F02)
|
||
|
|
#
|
||
|
|
# The last one is a REGEX on purpose: it is the ONLY browser-facing API path at
|
||
|
|
# the ROOT, and a plain prefix would swallow the web's `/datasets/[id]` page.
|
||
|
|
#
|
||
|
|
# With web + API on ONE origin there is no cross-origin request, so CORS is moot
|
||
|
|
# and the session cookie stays host-only (no `SESSION_COOKIE_DOMAIN`).
|
||
|
|
#
|
||
|
|
# `${PUBLIC_HOST}` is substituted by the nginx image's envsubst step.
|
||
|
|
# This is HTTP; add `listen 443 ssl` + certificates when TLS terminates here.
|
||
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
# Uploads (F02) can be several MB — nginx's 1m default would answer 413.
|
||
|
|
client_max_body_size 100m;
|
||
|
|
|
||
|
|
server {
|
||
|
|
listen 80;
|
||
|
|
server_name ${PUBLIC_HOST};
|
||
|
|
|
||
|
|
# Inherited by every `location` below.
|
||
|
|
proxy_set_header Host $host;
|
||
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
|
|
# better-auth checks the browser's Origin against WEB_URL; forward it as-is.
|
||
|
|
proxy_set_header Origin $http_origin;
|
||
|
|
|
||
|
|
# ── API ──────────────────────────────────────────────────────────────────
|
||
|
|
location = /health { proxy_pass http://api:13000; }
|
||
|
|
location /docs { proxy_pass http://api:13000; }
|
||
|
|
location /api/ { proxy_pass http://api:13000; }
|
||
|
|
location /public/ { proxy_pass http://api:13000; }
|
||
|
|
location /ingest/ { proxy_pass http://api:13000; }
|
||
|
|
|
||
|
|
# The one root-level browser API path (see the header note). Regex locations
|
||
|
|
# are evaluated BEFORE the prefix `location /` below, so this wins.
|
||
|
|
location ~ ^/datasets/[^/]+/versions/[^/]+/download$ {
|
||
|
|
proxy_pass http://api:13000;
|
||
|
|
}
|
||
|
|
|
||
|
|
# ── Web (everything else) ────────────────────────────────────────────────
|
||
|
|
location / { proxy_pass http://web:13001; }
|
||
|
|
}
|