# syntax=docker/dockerfile:1 # --- build stage: compile TypeScript + better-sqlite3's native binding --- FROM node:20-alpine AS build WORKDIR /app # python3/make/g++ are needed for node-gyp to build better-sqlite3 from source RUN apk add --no-cache python3 make g++ RUN npm install -g pnpm@9 COPY package.json pnpm-lock.yaml ./ # pnpm.onlyBuiltDependencies in package.json allows the better-sqlite3 # postinstall (native compile) to run non-interactively RUN pnpm install --frozen-lockfile COPY tsconfig.json ./ COPY src ./src RUN pnpm build # drop devDependencies, keep the already-compiled better-sqlite3 binding RUN pnpm prune --prod # --- runtime stage --- FROM node:20-alpine WORKDIR /app ENV NODE_ENV=production ENV PORT=3000 ENV HOST=0.0.0.0 COPY --from=build /app/node_modules ./node_modules COPY --from=build /app/dist ./dist COPY --from=build /app/package.json ./package.json COPY public ./public # data/app.db lives here; mount a host folder here to persist it, e.g.: # docker run -v /srv/hardingsclocks/data:/app/data ... # node:alpine ships a "node" user at uid/gid 1000 — chown the host folder to # 1000:1000 (or match this container's uid if you change it) so it's writable. RUN mkdir -p /app/data && chown -R node:node /app/data USER node EXPOSE 3000 CMD ["node", "dist/server.js"]