# Peikarband Platform - Production Dockerfile # Multi-stage build for optimized image size and security # Uses pre-built base image for faster builds # Build arguments ARG BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest ARG VERSION=latest ARG BUILD_DATE # ============================================ # Stage 1: Builder (using base image) # ============================================ FROM ${BASE_IMAGE} AS builder # Re-declare ARGs for this stage ARG VERSION=latest ARG BUILD_DATE LABEL maintainer="Peikarband Team " LABEL org.opencontainers.image.title="Peikarband Landing" LABEL org.opencontainers.image.description="Peikarband hosting platform landing page" LABEL org.opencontainers.image.version="${VERSION}" LABEL org.opencontainers.image.created="${BUILD_DATE}" WORKDIR /build # Base image already has: # - Python 3.11 # - Node.js 20 # - bun # - gcc, g++, make # - npm configured with retries # Verify tools are available RUN echo "=== Build Environment ===" && \ python --version && \ node --version && \ npm --version && \ bun --version && \ echo "========================" # Copy only requirements first (for better layer caching) COPY peikarband/requirements.txt . # Install Python dependencies in user space RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \ pip install --no-cache-dir --user -r requirements.txt # Copy application code (excluding .dockerignore items) COPY --chown=root:root peikarband/ . # Build and export Reflex app for production # Note: API_URL will be updated at runtime from environment variable # Export creates .web directory with frontend static files # Retry mechanism for network issues RUN set -ex && \ echo "Starting Reflex export (attempt 1)..." && \ python -m reflex export --no-zip --loglevel debug || \ (echo "Attempt 1 failed, cleaning cache..." && \ npm cache clean --force && \ rm -rf node_modules .web && \ sleep 15 && \ echo "Retrying (attempt 2)..." && \ python -m reflex export --no-zip --loglevel debug) || \ (echo "Attempt 2 failed, final retry..." && \ npm cache clean --force && \ rm -rf node_modules .web && \ sleep 20 && \ echo "Final attempt (3)..." && \ python -m reflex export --no-zip --loglevel debug) # Aggressive cleanup to reduce layer size # NOTE: Keep .web directory - it contains frontend static files RUN set -ex && \ # Remove Python cache find /build -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true && \ find /build -type f -name "*.pyc" -delete && \ find /build -type f -name "*.pyo" -delete && \ # Remove development files rm -rf /build/tests /build/docs /build/tools && \ rm -rf /build/.git /build/.github /build/.vscode && \ rm -rf /build/venv /build/env && \ # Remove node_modules but KEEP .web (frontend static files) rm -rf /build/node_modules && \ # Remove large duplicate assets from root rm -f /build/*.gif /build/*.mp4 /build/*.mov 2>/dev/null || true && \ # Keep only necessary configs find /build -type f -name "docker-compose*.yml" -delete && \ find /build -type f -name "Makefile" -delete # ============================================ # Stage 2: Runtime # ============================================ FROM python:${PYTHON_VERSION}-slim # Re-declare ARGs for this stage ARG PYTHON_VERSION=3.11 ARG VERSION=latest ARG BUILD_DATE # Build info ENV VERSION=${VERSION} \ BUILD_DATE=${BUILD_DATE} WORKDIR /app # Install runtime dependencies only RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ tini \ && rm -rf /var/lib/apt/lists/* \ && apt-get clean # Install Node.js runtime ARG NODE_VERSION=20 RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \ && apt-get install -y --no-install-recommends nodejs \ && rm -rf /var/lib/apt/lists/* \ && apt-get clean # Create non-root user first RUN groupadd -r -g 1000 peikarband && \ useradd -r -u 1000 -g peikarband -m -s /bin/bash peikarband && \ mkdir -p /app/logs /app/uploads /app/.reflex # Copy Python dependencies from builder to user home COPY --from=builder /root/.local /home/peikarband/.local # Copy application code from builder COPY --from=builder /build /app # Copy and set up runtime script COPY --chown=peikarband:peikarband peikarband/tools/scripts/update-env-json.sh /app/tools/scripts/update-env-json.sh RUN chmod +x /app/tools/scripts/update-env-json.sh # Fix ownership RUN chown -R peikarband:peikarband /home/peikarband/.local /app # Add version info (must be before USER switch) RUN echo "${VERSION}" > /app/.version && \ chown peikarband:peikarband /app/.version # Security: Remove unnecessary setuid/setgid permissions RUN find / -perm /6000 -type f -exec chmod a-s {} \; 2>/dev/null || true # Set environment variables ENV PATH=/home/peikarband/.local/bin:$PATH \ PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ PYTHONHASHSEED=random \ PIP_NO_CACHE_DIR=1 \ PIP_DISABLE_PIP_VERSION_CHECK=1 \ REFLEX_ENV=prod \ ENVIRONMENT=prod # Switch to non-root user USER peikarband # Expose ports EXPOSE 3000 8000 # Health check with better error handling HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD curl -f -s -o /dev/null -w "%{http_code}" http://localhost:8000/ping | grep -q "200" || exit 1 # Use tini as init system for proper signal handling # Update .web/env.json from API_URL env var, then run the app ENTRYPOINT ["/usr/bin/tini", "--", "/app/tools/scripts/update-env-json.sh"] # Run application (both frontend and backend) CMD ["python", "-m", "reflex", "run", "--env", "prod"]