Dockerfile
1,517 bytes
| 1 | # syntax=docker/dockerfile:1 |
|---|---|
| 2 | |
| 3 | # VoiceTask as a public demo: one container serving the built client and the API |
| 4 | # from a single origin, on the deterministic offline mock providers. |
| 5 | # |
| 6 | # The server runs from TypeScript through tsx rather than from tsc output. The |
| 7 | # compiled files keep their extensionless imports, which Node's ESM loader does |
| 8 | # not resolve, and tsx is the same path `npm run demo` uses locally. |
| 9 | |
| 10 | FROM node:24-bookworm-slim AS build |
| 11 | WORKDIR /app |
| 12 | COPY package*.json ./ |
| 13 | RUN npm ci |
| 14 | COPY . . |
| 15 | RUN npm run build:client |
| 16 | |
| 17 | FROM node:24-bookworm-slim AS runner |
| 18 | WORKDIR /app |
| 19 | ENV NODE_ENV=production |
| 20 | ENV PORT=3000 |
| 21 | # Public mode: no filesystem routes, no settings writes, sessions confined to |
| 22 | # the sandbox below, and the offline mocks locked on. |
| 23 | ENV VOICETASK_PUBLIC=1 |
| 24 | ENV VOICETASK_SANDBOX=/app/data/public-sessions |
| 25 | ENV VOICETASK_CLIENT_DIR=/app/dist/client |
| 26 | |
| 27 | COPY package*.json ./ |
| 28 | RUN npm ci --omit=dev \ |
| 29 | && npm install --no-save "tsx@$(node -p "require('./package.json').devDependencies.tsx")" \ |
| 30 | && npm cache clean --force |
| 31 | |
| 32 | COPY server ./server |
| 33 | COPY shared ./shared |
| 34 | COPY --from=build /app/dist/client ./dist/client |
| 35 | |
| 36 | # Every visitor's spec pack is written under here, and nowhere else. |
| 37 | RUN mkdir -p /app/data/public-sessions && chown -R node:node /app/data |
| 38 | |
| 39 | USER node |
| 40 | EXPOSE 3000 |
| 41 | |
| 42 | HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ |
| 43 | CMD node -e "fetch('http://127.0.0.1:3000/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))" |
| 44 | |
| 45 | CMD ["npx", "tsx", "server/index.ts"] |
| 46 | |