Spaces:
Paused
Paused
| # Build stage | |
| FROM node:20-alpine AS builder | |
| WORKDIR /app | |
| # Copy package files | |
| COPY package*.json ./ | |
| COPY tsconfig.json ./ | |
| # Install dependencies | |
| RUN npm ci | |
| # Copy source code | |
| COPY src ./src | |
| # Build the application | |
| RUN npm run build | |
| # Production stage | |
| FROM node:20-alpine | |
| WORKDIR /app | |
| # Install dumb-init for proper signal handling | |
| RUN apk add --no-cache dumb-init | |
| # Create non-root user | |
| RUN addgroup -g 1001 -S nodejs && \ | |
| adduser -S nodejs -u 1001 | |
| # Copy package files | |
| COPY package*.json ./ | |
| # Install production dependencies only | |
| RUN npm ci --only=production && \ | |
| npm cache clean --force | |
| # Copy built application from builder | |
| COPY --from=builder /app/dist ./dist | |
| # Change ownership | |
| RUN chown -R nodejs:nodejs /app | |
| # Switch to non-root user | |
| USER nodejs | |
| # Expose port | |
| EXPOSE 4000 | |
| # Health check | |
| HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ | |
| CMD node -e "require('http').get('http://localhost:4000/health/live', (r) => r.statusCode === 200 ? process.exit(0) : process.exit(1))" | |
| # Use dumb-init to handle signals properly | |
| ENTRYPOINT ["dumb-init", "--"] | |
| CMD ["node", "dist/index.js"] |