Files
support-fins/nginx.conf
kodin00 b401a656d1 docker: add compose + nginx image for one-command local deploy
The web app is a buildless static SPA (three.js is vendored in web/), so the
deploy image is just nginx serving web/ on :80. This adds:

- Dockerfile: nginx:stable-alpine, copies web/ + LICENSE, OCI labels.
- nginx.conf: port 80 site config that mirrors web/_redirects
  (/index.html and /index 301 -> /) via a $request_uri guard that cannot
  loop with the `index` directive's internal redirect; cache policy mirrors
  dev-server.py (no-store on the app's own JS/CSS/HTML) while long-caching
  the vendored three.js tree (immutable per image tag); absolute_redirect
  off so the redirect stays relative behind a reverse proxy.
- docker-compose.yml: one `web` service, host 8731:80 so the URL matches
  `python3 dev-server.py`, with a wget healthcheck.
- .dockerignore: excludes prototype/, plugin/, tests/, docs/, the dev
  servers and model files so the build context is just the web artifact.
- README: "Run with Docker" block pointing at the new files.

Validated: image builds, `nginx -t` passes, GET / -> 200 no-store,
GET /index.html|/index -> 301 relative /, GET /vendor/... -> immutable
long-cache, no redirect loop on /.
2026-09-21 20:29:14 +07:00

51 lines
2.1 KiB
Nginx Configuration File

# Support Fins -- nginx site config (mounted at /etc/nginx/conf.d/default.conf).
#
# Serves the buildless SPA from /usr/share/nginx/html on :80. The cache policy
# mirrors the Python dev server (no-store on the app's own JS/CSS/HTML, since
# there is no build/hash step and modules can change between image tags) while
# long-caching the vendored three.js tree, which is immutable per image tag.
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Emit relative redirects (Location: /) so the redirect target doesn't bake
# in a host:port that may be wrong behind a reverse proxy or when the
# container is published on a different host port.
absolute_redirect off;
# Default: never cache. The app has no build step and no content hashes, so
# a stale cached module would run the previous deploy's code -- the same
# hazard the dev server exists to prevent. Overridden below for assets that
# are immutable per image tag.
add_header Cache-Control "no-store, must-revalidate";
# Canonicalize the root URL -- mirrors web/_redirects (Cloudflare Pages):
# the app is served at "/", so /index.html and /index should 301 home and
# never be linkable or indexed as duplicates.
#
# $request_uri is the ORIGINAL client URI and is preserved across the
# internal redirect the `index` directive issues for "/", so matching it
# (not $uri) cannot loop with that internal redirect.
if ($request_uri ~ ^/index(\.html)?(\?|$)) { return 301 /; }
# Vendored three.js is immutable for the life of an image tag -- cache for a
# year. `^~` makes this prefix match win over any regex location below.
location ^~ /vendor/ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
# Icons and web manifest rarely change.
location ~* \.(svg|png|ico|webmanifest)$ {
add_header Cache-Control "public, max-age=86400";
}
gzip on;
gzip_types text/css text/javascript application/javascript application/json image/svg+xml;
gzip_vary on;
}