Files
mimic-big/frontend/nginx.conf
knacky 649194b174
Some checks failed
ci / backend (lint + typecheck + unit tests) (push) Failing after 1s
ci / frontend (lint + typecheck + build + unit tests) (push) Failing after 0s
chore(frontend): add multi-stage Dockerfile + nginx SPA config
Production image for the frontend dist.

Stage 1 (build): node:22-alpine, `npm ci --ignore-scripts` from the
committed lockfile, `npm run build`. Output lands in /app/dist.

Stage 2 (runtime): docker.io/nginxinc/nginx-unprivileged:alpine.
- Upstream-maintained variant that runs as the nginx user (uid 101)
  out of the box. /var/cache/nginx and /var/run/nginx are pre-owned,
  no chown gymnastics needed in our layer. Vanilla nginx:alpine fails
  at startup as non-root because client_temp mkdir is denied.
- Listens on 8080 (non-privileged port, matches the unprivileged
  variant convention).
- nginx.conf serves /usr/share/nginx/html with SPA `try_files`
  fallback for client-side routing, long-cache headers on
  /assets/ (Vite hashed bundles), a plaintext /healthz endpoint
  for Caddy / Prometheus blackbox, and server_tokens off.

.dockerignore excludes node_modules, dist, .vite, coverage,
playwright-report, .env*, .git, editor dirs. Keeps .env.example.

Smoke local validated with `podman build -t mimic-frontend:smoke .`
and `podman run -p 127.0.0.1:18080:8080`:
  /healthz -> 200 "ok"
  /        -> 200 index.html (508 B)
  /spa/x   -> 200 (SPA fallback)
  /assets  -> Cache-Control: max-age=31536000, public, immutable
2026-05-22 19:59:09 +02:00

31 lines
709 B
Nginx Configuration File

server {
listen 8080;
server_name _;
root /usr/share/nginx/html;
index index.html;
# SPA routing: every unknown path falls back to index.html.
location / {
try_files $uri $uri/ /index.html;
}
# Long-cache hashed asset bundles emitted by Vite under /assets/.
location /assets/ {
access_log off;
expires 1y;
add_header Cache-Control "public, immutable";
}
# Health endpoint scraped by Caddy / Prometheus blackbox.
location = /healthz {
access_log off;
default_type text/plain;
return 200 "ok\n";
}
# No directory listing, no server tokens.
autoindex off;
server_tokens off;
}