84 lines
2.6 KiB
Nginx Configuration File
84 lines
2.6 KiB
Nginx Configuration File
# Cyclone frontend — nginx site config.
|
|
#
|
|
# Two responsibilities:
|
|
# 1. Serve the built SPA bundle from /usr/share/nginx/html with a
|
|
# fallback to index.html for client-side routing.
|
|
# 2. Reverse-proxy /api/* to the backend service so the SPA can call
|
|
# relative URLs (VITE_API_BASE_URL empty) without CORS round-trips.
|
|
#
|
|
# `backend` resolves via Docker's user-defined network (compose service
|
|
# name). `chunked_transfer_encoding off` keeps SSE/NDJSON streams flowing
|
|
# instead of being buffered by nginx — uvicorn already streams, but the
|
|
# explicit override makes the intent obvious and survives future nginx
|
|
# default changes.
|
|
|
|
upstream cyclone_backend {
|
|
server backend:8000;
|
|
keepalive 16;
|
|
}
|
|
|
|
server {
|
|
listen 80;
|
|
server_name _;
|
|
|
|
root /usr/share/nginx/html;
|
|
index index.html;
|
|
|
|
# Reasonable defaults for a single-operator dashboard.
|
|
client_max_body_size 25m;
|
|
|
|
# gzip JS/CSS/JSON/SVG so the initial bundle loads faster.
|
|
gzip on;
|
|
gzip_comp_level 5;
|
|
gzip_min_length 256;
|
|
gzip_proxied any;
|
|
gzip_vary on;
|
|
gzip_types
|
|
application/javascript
|
|
application/json
|
|
application/xml
|
|
image/svg+xml
|
|
text/css
|
|
text/plain;
|
|
|
|
# Cache fingerprinted assets aggressively; index.html stays fresh.
|
|
location ~* \.(?:js|css|woff2?|ttf|otf|eot|svg|png|jpg|jpeg|webp|ico)$ {
|
|
try_files $uri =404;
|
|
expires 7d;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
|
|
# /api/* → backend. Don't buffer so live-tail NDJSON streams flow.
|
|
location /api/ {
|
|
proxy_pass http://cyclone_backend;
|
|
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_set_header Connection "";
|
|
|
|
# Keep idle NDJSON streams alive across nginx's default 60s.
|
|
proxy_read_timeout 1h;
|
|
proxy_send_timeout 60s;
|
|
proxy_buffering off;
|
|
proxy_cache off;
|
|
chunked_transfer_encoding on;
|
|
add_header X-Accel-Buffering no;
|
|
}
|
|
|
|
# SPA fallback — anything that isn't a real file in / serves index.html
|
|
# so client-side routes (/inbox, /claims/:id) don't 404 on refresh.
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
|
|
# Lightweight health probe for orchestrators that prefer /healthz over
|
|
# the static index.
|
|
location = /healthz {
|
|
access_log off;
|
|
add_header Content-Type text/plain;
|
|
return 200 "ok\n";
|
|
}
|
|
} |