# ============================================================================== # Stage 1: Build the static frontend export # ============================================================================== FROM node:20-alpine AS frontend-builder WORKDIR /app/frontend RUN apk add --no-cache libc6-compat COPY refer_landing_page/package.json refer_landing_page/package-lock.json ./ RUN npm ci COPY refer_landing_page/ . ARG NEXT_PUBLIC_API_BASE_URL="" ENV NEXT_PUBLIC_API_BASE_URL=${NEXT_PUBLIC_API_BASE_URL} \ NEXT_TELEMETRY_DISABLED=1 \ NODE_ENV=production RUN npm run build # ============================================================================== # Stage 2: Build the Go binaries # ============================================================================== FROM golang:1.26-alpine AS backend-builder WORKDIR /app RUN apk add --no-cache git ca-certificates tzdata COPY backend/go.mod backend/go.sum ./ RUN go mod download COPY backend/ . RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /bin/api ./cmd/api && \ CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /bin/seed ./cmd/seed && \ CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /bin/export-content ./cmd/export-content # ============================================================================== # Stage 3: Minimal Alpine runtime — single container, single process # ============================================================================== FROM alpine:3.20 WORKDIR /app RUN apk add --no-cache ca-certificates tzdata sqlite curl && \ addgroup -S appgroup && adduser -S appuser -G appgroup RUN mkdir -p /app/data && chown -R appuser:appgroup /app/data COPY --from=backend-builder /bin/api /app/bin/api COPY --from=backend-builder /bin/seed /app/bin/seed COPY --from=backend-builder /bin/export-content /app/bin/export-content COPY --from=backend-builder /app/seed /app/seed COPY --from=backend-builder /app/.env.example /app/.env COPY --from=frontend-builder --chown=appuser:appgroup /app/frontend/out /app/web ENV HOST=0.0.0.0 \ PORT=8080 \ DB_PATH=/app/data/anl.db \ GIN_MODE=release \ CORS_ALLOW_ORIGINS=* \ AUTO_MIGRATE=true EXPOSE 8080 USER appuser HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8080/api/v1/health || exit 1 ENTRYPOINT ["/app/bin/api"]