# syntax=docker/dockerfile:1 # Single image used by both the web and worker services (see docker-compose.yml). # Includes ffmpeg (audio stitching) + the full node_modules so the worker can run # via tsx and `prisma migrate deploy` can run on web startup. FROM node:20-bookworm-slim AS base RUN apt-get update \ && apt-get install -y --no-install-recommends ffmpeg openssl ca-certificates \ && rm -rf /var/lib/apt/lists/* WORKDIR /app ENV NEXT_TELEMETRY_DISABLED=1 # ---- dependencies ---- FROM base AS deps COPY package.json package-lock.json ./ RUN npm ci # ---- build ---- FROM base AS build COPY --from=deps /app/node_modules ./node_modules COPY . . # NEXT_PUBLIC_* are inlined into the client bundle at build time, so they must be # provided as build args (Dokploy passes them from the env — see docker-compose.yml). ARG NEXT_PUBLIC_APP_URL ARG NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ENV NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL ENV NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=$NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY # A throwaway BETTER_AUTH_SECRET, scoped to THIS command only (not a persisted ENV # layer), satisfies the prod-secret guard in lib/auth/auth.ts during `next build`. # Dokploy injects the real secret at run time; it's never baked into the bundle. RUN BETTER_AUTH_SECRET=build-time-placeholder npm run build # ---- runtime ---- FROM base AS runner ENV NODE_ENV=production ENV PORT=3000 ENV HOSTNAME=0.0.0.0 ENV STORAGE_DIR=/app/storage # Copy the whole built app (node_modules incl. tsx + prisma CLI, .next, source). COPY --from=build /app ./ RUN mkdir -p /app/storage/mp3 /app/storage/art /app/storage/exports EXPOSE 3000 # Default = web; the worker service overrides this command in docker-compose.yml. CMD ["npm", "run", "start"]