55 lines
1.9 KiB
Docker
55 lines
1.9 KiB
Docker
# `output: 'standalone'` in next.config.ts (no custom server here, unlike
|
|||
|
|
# pulsenode's, so standalone is viable) traces only what's actually required
|
||
|
|
# and copies better-sqlite3's compiled native binary along with it - verified
|
||
|
|
# by inspecting .next/standalone/node_modules after a local build.
|
||
|
|
|
||
|
|
FROM node:22-alpine AS base
|
||
|
|
RUN corepack enable
|
||
|
|
|
||
|
|
FROM base AS deps
|
||
|
|
WORKDIR /app
|
||
|
|
# better-sqlite3 ships prebuilt binaries for linux-musl (this image's libc),
|
||
|
|
# but the toolchain is installed defensively in case no prebuild matches this
|
||
|
|
# Node version - prebuild-install falls back to compiling from source then.
|
||
|
|
RUN apk add --no-cache python3 make g++
|
||
|
|
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||
|
|
RUN pnpm install --frozen-lockfile
|
||
|
|
|
||
|
|
FROM base AS build
|
||
|
|
WORKDIR /app
|
||
|
|
COPY --from=deps /app/node_modules ./node_modules
|
||
|
|
COPY . .
|
||
|
|
RUN pnpm build
|
||
|
|
|
||
|
|
FROM node:22-alpine AS runtime
|
||
|
|
RUN apk add --no-cache tini
|
||
|
|
WORKDIR /app
|
||
|
|
ENV NODE_ENV=production
|
||
|
|
# Docker auto-sets HOSTNAME to the container id; the standalone server.js
|
||
|
|
# binds to `process.env.HOSTNAME || '0.0.0.0'`, so left unset it would bind
|
||
|
|
# only to that container-id hostname's address instead of all interfaces,
|
||
|
|
# making the app unreachable via the published port.
|
||
|
|
ENV HOSTNAME=0.0.0.0
|
||
|
|
|
||
|
|
RUN addgroup -g 10001 -S app && adduser -u 10001 -S app -G app
|
||
|
|
|
||
|
|
# Standalone output ships its own minimal node_modules + server.js; static
|
||
|
|
# assets, public/, and the drizzle migrations aren't traced (they're read
|
||
|
|
# from disk at runtime, not imported), so they're copied in separately.
|
||
|
|
COPY --from=build /app/.next/standalone ./
|
||
|
|
COPY --from=build /app/.next/static ./.next/static
|
||
|
|
COPY --from=build /app/public ./public
|
||
|
|
COPY --from=build /app/drizzle ./drizzle
|
||
|
|
COPY --from=build /app/healthcheck.mjs ./healthcheck.mjs
|
||
|
|
|
||
|
|
RUN mkdir -p /app/data && chown -R app:app /app
|
||
|
|
|
||
|
|
USER app
|
||
|
|
EXPOSE 3000
|
||
|
|
|
||
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||
|
|
CMD ["node", "healthcheck.mjs"]
|
||
|
|
|
||
|
|
ENTRYPOINT ["tini", "--"]
|
||
|
|
CMD ["node", "server.js"]
|