# Multi-stage build for better reliability FROM node:22-bookworm-slim as base # Install system dependencies in a single layer to reduce image size RUN apt-get update && apt-get install -y \ libnss3 \ libdbus-1-3 \ libatk1.0-0 \ libgbm-dev \ libasound2 \ libxrandr2 \ libxkbcommon-dev \ libxfixes3 \ libxcomposite1 \ libxdamage1 \ libatk-bridge2.0-0 \ libpango-1.0-0 \ libcairo2 \ libcups2 \ bash \ git git-lfs \ wget curl procps \ htop vim nano \ xz-utils \ xvfb x11-utils \ nginx \ ca-certificates \ && rm -rf /var/lib/apt/lists/* \ && apt-get clean # Install FFmpeg 8 from static build with error handling RUN set -e && \ wget --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 -t 3 \ https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \ tar -xf ffmpeg-release-amd64-static.tar.xz && \ mv ffmpeg-*-amd64-static/ffmpeg /usr/local/bin/ffmpeg && \ mv ffmpeg-*-amd64-static/ffprobe /usr/local/bin/ffprobe && \ chmod +x /usr/local/bin/ffmpeg /usr/local/bin/ffprobe && \ rm -rf ffmpeg-* && \ ln -sf /usr/local/bin/ffmpeg /usr/bin/ffmpeg && \ ln -sf /usr/local/bin/ffprobe /usr/bin/ffprobe && \ ffmpeg -version # Common-utils build stage - build the local common-utils dependency FROM base as common-utils-builder RUN mkdir /app && chown 1000 /app USER 1000 WORKDIR /app # Copy common-utils source and package files COPY --chown=1000 common-utils/ ./common-utils/ # Install TypeScript globally for building common-utils USER root RUN npm install -g typescript USER 1000 # Build common-utils - install dependencies and compile WORKDIR /app/common-utils RUN npm install && \ npm run build && \ echo "Common-utils build completed successfully" # Dependencies stage - isolate dependency installation FROM base as dependencies RUN mkdir /app && chown 1000 /app USER 1000 WORKDIR /app # Copy package files and npm config first for better caching COPY --chown=1000 package*.json ./ COPY --chown=1000 .npmrc ./ # Copy built common-utils from the builder stage COPY --from=common-utils-builder --chown=1000 /app/common-utils ./common-utils # Set comprehensive npm configurations for reliability and speed RUN npm config set fetch-retry-mintimeout 20000 && \ npm config set fetch-retry-maxtimeout 120000 && \ npm config set fetch-retries 5 && \ npm config set fetch-timeout 600000 && \ npm config set registry https://registry.npmjs.org/ && \ npm config set audit false && \ npm config set fund false && \ npm config set update-notifier false # Environment variables to skip problematic binary downloads ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true ENV PUPPETEER_SKIP_DOWNLOAD=true ENV SKIP_FFMPEG_DOWNLOAD=true ENV SHARP_IGNORE_GLOBAL_LIBVIPS=1 ENV NODE_ENV=production ENV CI=true # Clear any existing npm cache to prevent corruption RUN npm cache clean --force # Install dependencies with multiple fallback strategies and comprehensive error handling # Note: NOT using --no-optional to allow esbuild platform-specific binaries to install # Skip preinstall script since we already built common-utils RUN set -e && \ echo "Starting dependency installation..." && \ (timeout 900 npm ci --verbose --ignore-scripts --production=false 2>&1 | tee /tmp/npm-install.log) || \ (echo "First attempt failed, cleaning cache and retrying..." && \ npm cache clean --force && \ rm -rf node_modules package-lock.json && \ timeout 900 npm install --verbose --ignore-scripts --production=false 2>&1 | tee -a /tmp/npm-install.log) || \ (echo "Second attempt failed, trying with reduced concurrency..." && \ npm cache clean --force && \ rm -rf node_modules && \ timeout 1200 npm install --verbose --maxsockets 1 --production=false 2>&1 | tee -a /tmp/npm-install.log) # Run postinstall scripts separately for better control and debugging # Skip the common-utils build in postinstall since we already have it built RUN echo "Running postinstall scripts..." && \ echo "Skipping common-utils build in postinstall as it's already built" && \ node ffmpeg-fix.js 2>&1 | tee -a /tmp/postinstall.log || echo "ffmpeg-fix completed" && \ npm rebuild --verbose 2>&1 | tee -a /tmp/npm-rebuild.log || \ echo "Some rebuilds failed, but continuing..." # Verify critical packages are installed RUN node -e "console.log('Node version:', process.version)" && \ node -e "require('react'); console.log('React OK')" && \ node -e "require('remotion'); console.log('Remotion OK')" && \ ls -la node_modules/.bin/ | head -20 # Final production stage FROM base as final # Create app directory and set permissions RUN mkdir -p /app /app/public /app/out /app/frames /app/uploads && chown -R 1000:1000 /app # Copy installed dependencies from the dependencies stage COPY --from=dependencies --chown=1000 /app/node_modules ./app/node_modules COPY --from=dependencies --chown=1000 /app/package*.json ./app/ COPY --from=dependencies --chown=1000 /app/common-utils ./app/common-utils USER 1000 WORKDIR /app # Copy application code (node_modules excluded via .dockerignore) COPY --chown=1000 . ./ # Ensure proper permissions for writable directories USER root RUN chmod -R 777 /app/public /app/out /app/uploads /app/frames || true && \ chmod 777 /app/index.html || true && \ mkdir -p /tmp/client_body /tmp/proxy_temp /tmp/fastcgi_temp /tmp/uwsgi_temp /tmp/scgi_temp && \ chmod -R 777 /tmp && \ chmod -R 777 /var && \ chmod -R 777 /app/node_modules/.cache || true # Copy nginx config and start script COPY --chown=1000 nginx.conf /etc/nginx/nginx.conf COPY --chown=1000 start.sh /app/start.sh RUN chmod +x /app/start.sh # Ensure nginx runs as root RUN sed -i 's/^user .*;/user root;/' /etc/nginx/nginx.conf || true USER 1000 # Ensure remotion browser is properly set up (do this after all dependencies are ready) RUN echo "Setting up Remotion browser..." && \ npx remotion browser ensure 2>&1 | tee /tmp/remotion-browser.log || \ echo "Browser setup had issues, but continuing..." # Verify the installation RUN echo "Verifying installation..." && \ node -e "console.log('Final verification - Node:', process.version)" && \ npm list --depth=0 | head -10 || true # Set up environment for runtime ENV DISPLAY=:99 ENV NODE_ENV=production # Expose required ports EXPOSE 7860 3000 8083 # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8083/ || exit 1 # Start the application CMD ["sh", "/app/start.sh"] # Build and run commands: # docker build -f Dockerfile.build.multistage -t render-farm:latest . # docker run -p 8083:8083 -it --rm render-farm:latest # docker run -p 8083:8083 -it --rm --entrypoint /bin/sh render-farm:latest