# ============================================ # Switchboard Core — Unified Dockerfile # ============================================ # Stage 1: Build Go backend # Stage 2: Download JS vendor libs (marked, DOMPurify) # Stage 3: Build CM6 editor bundle (esbuild) # Stage 4: Build bundled packages (.pkg archives) # Stage 5: Production image (nginx + backend) # # Vendor libs are baked in during build so the # app works in disconnected environments # with no CDN access. # ============================================ # ── Stage 1: Go backend build ──────────────── FROM golang:1.23-bookworm AS backend WORKDIR /app COPY server/go.mod server/go.sum* ./ COPY server/ . COPY VERSION ./ RUN go mod download && go mod tidy && go mod verify RUN CGO_ENABLED=0 go build -ldflags="-s -w -X main.Version=$(cat VERSION)" -o /bin/switchboard . # ── Stage 2: Vendor JS libs ───────────────── FROM node:20-alpine AS vendor WORKDIR /vendor RUN npm pack marked@16.3.0 && \ tar xzf marked-16.3.0.tgz && \ cp package/lib/marked.umd.js marked.min.js && \ rm -rf package marked-16.3.0.tgz RUN npm pack dompurify@3.2.4 && \ tar xzf dompurify-3.2.4.tgz && \ cp package/dist/purify.min.js purify.min.js && \ rm -rf package dompurify-3.2.4.tgz RUN npm pack mermaid@11.4.1 && \ tar xzf mermaid-11.4.1.tgz && \ mkdir -p mermaid && \ cp package/dist/mermaid.min.js mermaid/mermaid.min.js && \ rm -rf package mermaid-11.4.1.tgz RUN npm pack katex@0.16.11 && \ tar xzf katex-0.16.11.tgz && \ mkdir -p katex && \ cp package/dist/katex.min.js katex/katex.min.js && \ cp package/dist/katex.min.css katex/katex.min.css && \ cp -r package/dist/fonts katex/fonts && \ rm -rf package katex-0.16.11.tgz # ── Stage 3: CM6 editor bundle ───────────── FROM node:20-alpine AS cm6-build WORKDIR /build COPY src/editor/ /build/src/editor/ COPY scripts/build-editor.sh /build/scripts/build-editor.sh RUN cd /build/src/editor && npm ci --loglevel=warn RUN sh /build/scripts/build-editor.sh /build/dist # ── Stage 4: Build bundled packages ───────── FROM alpine:3 AS packages RUN apk add --no-cache zip bash COPY packages/ /packages/ RUN cd /packages && bash build.sh # ── Stage 5: Production ───────────────────── FROM nginx:1-alpine RUN apk add --no-cache bash git # Go backend binary COPY --from=backend /bin/switchboard /usr/local/bin/switchboard COPY --from=backend /app/database/migrations /app/database/migrations # Frontend static files COPY src/ /usr/share/nginx/html/ COPY VERSION /VERSION # Inject version and build hash into index.html and sw.js at build time RUN APP_VERSION=$(cat /VERSION | tr -d '[:space:]') && \ BUILD_HASH=$(find /usr/share/nginx/html/js -name '*.js' -exec md5sum {} + | sort | md5sum | cut -c1-8) && \ sed -i "s|%%APP_VERSION%%|${APP_VERSION}|g" /usr/share/nginx/html/index.html && \ sed -i -e "s|%%APP_VERSION%%|${APP_VERSION}|g" -e "s|%%BUILD_HASH%%|${BUILD_HASH}|g" /usr/share/nginx/html/sw.js # Vendor libs (overwrite any existing copies in src/vendor/) COPY --from=vendor /vendor/marked.min.js /usr/share/nginx/html/vendor/marked.min.js COPY --from=vendor /vendor/purify.min.js /usr/share/nginx/html/vendor/purify.min.js COPY --from=vendor /vendor/mermaid/mermaid.min.js /usr/share/nginx/html/vendor/mermaid/mermaid.min.js COPY --from=vendor /vendor/katex/katex.min.js /usr/share/nginx/html/vendor/katex/katex.min.js COPY --from=vendor /vendor/katex/katex.min.css /usr/share/nginx/html/vendor/katex/katex.min.css COPY --from=vendor /vendor/katex/fonts/ /usr/share/nginx/html/vendor/katex/fonts/ COPY --from=cm6-build /build/dist/ /usr/share/nginx/html/vendor/codemirror/ # Bundled packages (v0.3.8) — auto-installed on first run COPY --from=packages /dist/ /app/bundled-packages/ # nginx config (template — envsubst injects BASE_PATH at runtime) COPY nginx.conf.template /etc/nginx/templates/default.conf.template # Only substitute BASE_PATH — preserve nginx variables ($host, $uri, etc.) ENV NGINX_ENVSUBST_FILTER="BASE_PATH" # Entrypoint: start Go backend, then nginx COPY docker-entrypoint.sh /docker-entrypoint.d/90-start-backend.sh RUN chmod +x /docker-entrypoint.d/90-start-backend.sh EXPOSE 80