feat(docker): add containerized nginx deployment with runtime base path

Two-stage build: node builds the static bundle, nginx serves it. The bundle is
built against a placeholder base token that the entrypoint rewrites to $BASE_URL
at start, so one image serves from any path without a rebuild.

nginx config caches hashed assets forever, never caches index.html, and applies
security headers (CSP, no framing, no referrer) suited to an app that handles
cloud credentials client-side.

.gitattributes pins LF on the container-consumed files, since core.autocrlf
would otherwise give the entrypoint a CRLF shebang.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-26 15:03:19 +02:00
co-authored by Claude Opus 5
parent 48802cf13c
commit 32159a404d
7 changed files with 149 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
# syntax=docker/dockerfile:1
# ---- Stage 1: build the static bundle ----
FROM node:22-alpine AS build
WORKDIR /app
# Deps from the lockfile first, so this layer survives source-only edits.
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
# Build against a placeholder base. The entrypoint swaps it for $BASE_URL at startup,
# so one image can be served from any path without rebuilding.
RUN npm run build -- --base=/__R2B_BASE__/
# ---- Stage 2: serve it ----
# Ready2Blob is entirely client-side, so the runtime image is just nginx + dist/.
FROM nginx:alpine AS runtime
# Pristine copy; the entrypoint stages it into the web root on each start.
COPY --from=build /app/dist /opt/ready2blob/html
COPY docker/security-headers.conf /etc/nginx/snippets/security-headers.conf
COPY docker/nginx.conf.template /etc/nginx/ready2blob.conf.template
COPY docker/40-ready2blob-base-url.sh /docker-entrypoint.d/40-ready2blob-base-url.sh
RUN chmod +x /docker-entrypoint.d/40-ready2blob-base-url.sh
# Path the app is served from. "/" for a dedicated (sub)domain, "/ready2blob/" when
# mounted under a path on a shared host.
ENV BASE_URL=/
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -q --spider http://localhost/ || exit 1