# syntax=docker/dockerfile:1.6 # # VYNDR Next.js frontend (port 3000). # # next.config.ts has `output: 'standalone'` set, so .next/standalone is a # self-contained runtime — no node_modules needed at runtime image. # # Three-stage build keeps the final image lean. The build runs with # `next build --webpack` (Serwist doesn't yet support Next 16 Turbopack # for production builds). # # Build: docker build -f web/Dockerfile -t vyndr-web . # Run: docker run -p 3000:3000 --env-file web/.env vyndr-web # --- deps stage --- FROM node:20-alpine AS deps WORKDIR /app COPY web/package.json web/package-lock.json ./ RUN npm ci --no-audit --no-fund # --- build stage --- FROM node:20-alpine AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY web/ ./ # NEXT_PUBLIC_* must be present at build time — Next.js inlines them. # Coolify passes them via build args (mapped to env vars). ARG NEXT_PUBLIC_SUPABASE_URL ARG NEXT_PUBLIC_SUPABASE_ANON_KEY ARG NEXT_PUBLIC_SITE_URL ARG NEXT_PUBLIC_VAPID_PUBLIC_KEY ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL \ NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY \ NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL \ NEXT_PUBLIC_VAPID_PUBLIC_KEY=$NEXT_PUBLIC_VAPID_PUBLIC_KEY \ NODE_ENV=production RUN npm run build # --- runner stage --- FROM node:20-alpine AS runner WORKDIR /app RUN apk add --no-cache curl tini ENV NODE_ENV=production \ PORT=3000 RUN addgroup -S vyndr && adduser -S vyndr -G vyndr # Standalone output bundles only what the server needs. COPY --from=builder --chown=vyndr:vyndr /app/.next/standalone ./ COPY --from=builder --chown=vyndr:vyndr /app/.next/static ./.next/static COPY --from=builder --chown=vyndr:vyndr /app/public ./public USER vyndr EXPOSE 3000 ENTRYPOINT ["/sbin/tini", "--"] HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \ CMD curl -fsS http://127.0.0.1:3000 || exit 1 CMD ["node", "server.js"]