# Build stage - compile frontend FROM node:20-alpine AS builder WORKDIR /app # Install dependencies first (better caching) COPY package*.json ./ ENV YOUTUBE_DL_SKIP_PYTHON_CHECK=1 RUN npm install # Copy source and build frontend COPY . . RUN npm run build # Production stage FROM node:20-alpine WORKDIR /app # Install yt-dlp, ffmpeg, and su-exec for privilege dropping # Using apk for Alpine Linux (small image size) RUN apk add --no-cache \ python3 \ py3-pip \ ffmpeg \ wget \ su-exec \ && pip3 install --break-system-packages --no-cache-dir yt-dlp # Copy package files and install production dependencies only COPY package*.json ./ RUN npm install --omit=dev # Copy built frontend from builder stage COPY --from=builder /app/build ./build # Copy server source (will be run with tsx) COPY server ./server # Create non-root user for security RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001 # Create uploads directory with proper permissions RUN mkdir -p /app/uploads && chmod 755 /app/uploads RUN chown -R nodejs:nodejs /app # Copy entrypoint script COPY docker-entrypoint.sh /docker-entrypoint.sh RUN chmod +x /docker-entrypoint.sh # Environment variables ENV NODE_ENV=production ENV PORT=3000 ENV HOST=0.0.0.0 # Expose port EXPOSE 3000 # Volume for persistent uploads (optional) VOLUME ["/app/uploads"] # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ CMD wget -q --spider http://localhost:3000/ || exit 1 # Use entrypoint to fix volume permissions then drop to nodejs user ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["npx", "tsx", "server/index.ts"]