# TimeSafari Docker Build # Author: Matthew Raymer # Description: Multi-stage Docker build for TimeSafari web application # # Build Process: # 1. Base stage: Node.js with build dependencies # 2. Builder stage: Compile web assets with Vite # 3. Production stage: Nginx server with optimized assets # # Security Features: # - Non-root user execution # - Minimal attack surface with Alpine Linux # - Multi-stage build to reduce image size # - No build dependencies in final image # # Usage: # Production: docker build -t timesafari:latest . # Staging: docker build --build-arg BUILD_MODE=staging -t timesafari:staging . # Development: docker build --build-arg BUILD_MODE=development -t timesafari:dev . # # Build Arguments: # BUILD_MODE: development, staging, or production (default: production) # NODE_ENV: node environment (default: production) # VITE_PLATFORM: vite platform (default: web) # VITE_PWA_ENABLED: enable PWA (default: true) # VITE_DISABLE_PWA: disable PWA (default: false) # # Environment Variables: # NODE_ENV: Build environment (development/production) # VITE_APP_SERVER: Application server URL # VITE_DEFAULT_ENDORSER_API_SERVER: Endorser API server URL # VITE_DEFAULT_IMAGE_API_SERVER: Image API server URL # VITE_DEFAULT_PARTNER_API_SERVER: Partner API server URL # VITE_DEFAULT_PUSH_SERVER: Push notification server URL # VITE_PASSKEYS_ENABLED: Enable passkeys feature # ============================================================================= # BASE STAGE - Common dependencies and setup # ============================================================================= FROM node:22-alpine3.20 AS base # Install system dependencies for build process RUN apk add --no-cache \ bash \ git \ python3 \ py3-pip \ py3-setuptools \ make \ g++ \ gcc \ && rm -rf /var/cache/apk/* # Create non-root user for security RUN addgroup -g 1001 -S nodejs && \ adduser -S nextjs -u 1001 # Set working directory WORKDIR /app # Copy package files for dependency installation COPY package*.json ./ # Install dependencies with security audit RUN npm ci --only=production --audit --fund=false && \ npm audit fix --audit-level=moderate || true # ============================================================================= # BUILDER STAGE - Compile web assets # ============================================================================= FROM base AS builder # Define build arguments with defaults ARG BUILD_MODE=production ARG NODE_ENV=production ARG VITE_PLATFORM=web ARG VITE_PWA_ENABLED=true ARG VITE_DISABLE_PWA=false # Set environment variables from build arguments ENV BUILD_MODE=${BUILD_MODE} ENV NODE_ENV=${NODE_ENV} ENV VITE_PLATFORM=${VITE_PLATFORM} ENV VITE_PWA_ENABLED=${VITE_PWA_ENABLED} ENV VITE_DISABLE_PWA=${VITE_DISABLE_PWA} # Install all dependencies (including dev dependencies) RUN npm ci --audit --fund=false && \ npm audit fix --audit-level=moderate || true # Copy source code COPY . . # Build the application with proper error handling RUN echo "Building TimeSafari in ${BUILD_MODE} mode..." && \ npm run build:web || (echo "Build failed. Check the logs above." && exit 1) # Verify build output exists RUN ls -la dist/ || (echo "Build output not found in dist/ directory" && exit 1) # ============================================================================= # PRODUCTION STAGE - Nginx server # ============================================================================= FROM nginx:alpine AS production # Define build arguments for production stage ARG BUILD_MODE=production ARG NODE_ENV=production # Set environment variables ENV BUILD_MODE=${BUILD_MODE} ENV NODE_ENV=${NODE_ENV} # Install security updates and clean cache RUN apk update && \ apk upgrade && \ apk add --no-cache \ curl \ && rm -rf /var/cache/apk/* # Create non-root user for nginx RUN addgroup -g 1001 -S nginx && \ adduser -S nginx -u 1001 -G nginx # Copy appropriate nginx configuration based on build mode COPY docker/nginx.conf /etc/nginx/nginx.conf COPY docker/default.conf /etc/nginx/conf.d/default.conf # Copy staging configuration if needed COPY docker/staging.conf /etc/nginx/conf.d/staging.conf # Copy built assets from builder stage COPY --from=builder --chown=nginx:nginx /app/dist /usr/share/nginx/html # Create necessary directories with proper permissions RUN mkdir -p /var/cache/nginx /var/log/nginx /var/run && \ chown -R nginx:nginx /var/cache/nginx /var/log/nginx /var/run && \ chown -R nginx:nginx /usr/share/nginx/html # Switch to non-root user USER nginx # Expose port 80 EXPOSE 80 # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost/ || exit 1 # Start nginx with proper signal handling CMD ["nginx", "-g", "daemon off;"] # ============================================================================= # DEVELOPMENT STAGE - For development with hot reloading # ============================================================================= FROM base AS development # Define build arguments for development stage ARG BUILD_MODE=development ARG NODE_ENV=development ARG VITE_PLATFORM=web ARG VITE_PWA_ENABLED=true ARG VITE_DISABLE_PWA=false # Set environment variables ENV BUILD_MODE=${BUILD_MODE} ENV NODE_ENV=${NODE_ENV} ENV VITE_PLATFORM=${VITE_PLATFORM} ENV VITE_PWA_ENABLED=${VITE_PWA_ENABLED} ENV VITE_DISABLE_PWA=${VITE_DISABLE_PWA} # Install all dependencies including dev dependencies RUN npm ci --audit --fund=false && \ npm audit fix --audit-level=moderate || true # Copy source code COPY . . # Expose development port EXPOSE 5173 # Start development server CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"] # ============================================================================= # STAGING STAGE - For staging environment testing # ============================================================================= FROM production AS staging # Define build arguments for staging stage ARG BUILD_MODE=staging ARG NODE_ENV=staging # Set environment variables ENV BUILD_MODE=${BUILD_MODE} ENV NODE_ENV=${NODE_ENV} # Copy staging-specific nginx configuration COPY docker/staging.conf /etc/nginx/conf.d/default.conf # Expose port 80 EXPOSE 80 # Health check for staging HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost/health || exit 1 # Start nginx CMD ["nginx", "-g", "daemon off;"]