fix(docker): serve SPA via hanzoai/spa, not hanzoai/static (#12)

hanzoai/static defaults to Content-Security-Policy: default-src 'none'
(no script-src) — built for static assets, not a SPA that loads its own
JS bundle. That CSP blocks index-*.js, so React never mounts and the
login page renders blank. hanzoai/spa is the purpose-built base: history-
API fallthrough for client-side routes + a SPA-safe CSP. Defaults
PORT=3000 / ROOT=/public, matching the id deploy probe.

Immediate prod was unblocked by setting HANZO_STATIC_CSP on the live
deployment; this is the durable, one-way fix so the override hack isn't
needed and every rebuild serves correctly.

Co-authored-by: Antje Worring <[email protected]>
This commit is contained in:
zooqueen
2026-06-18 16:14:27 -07:00
committed by GitHub
co-authored by Antje Worring
parent 09a60d471a
commit c07370a506
+9 -7
View File
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1.7
# Hanzo ID — Vite SPA built once, served by hanzoai/static.
# Hanzo ID — Vite SPA built once, served by hanzoai/spa.
FROM node:24-alpine AS build
WORKDIR /build
ENV PNPM_HOME=/pnpm PATH=$PNPM_HOME:$PATH
@@ -16,10 +16,12 @@ COPY apps apps
COPY pkgs pkgs
RUN pnpm --filter @hanzo/id-web build
# Static server stage — hanzoai/static reads /spa for assets
FROM ghcr.io/hanzoai/static:0.4.1
COPY --from=build /build/apps/web/dist /spa
# SPA server stage — hanzoai/spa is the correct base for a Vite SPA:
# history-API fallthrough for client-side routes AND a SPA-safe CSP.
# hanzoai/static defaults to `Content-Security-Policy: default-src 'none'`
# (built for static assets, not an app that loads its own bundle), which
# blocks the SPA's own scripts and leaves a blank page. hanzoai/spa serves
# index.html for all routes with a sane CSP. Defaults: PORT=3000, ROOT=/public.
FROM ghcr.io/hanzoai/spa:1.3.0
COPY --from=build /build/apps/web/dist /public
EXPOSE 3000
# hanzoai/static reads -root/-spa as FLAGS (ROOT/PORT env are ignored);
# default port 3000 matches the id deploy probe.
ENTRYPOINT ["/static", "-root", "/spa", "-spa"]