# ============================================================ # Dockerfile — Full application (frontend + backend) # ============================================================ # Multi-stage build: # 1. chef – install cargo-chef for dependency caching # 2. planner – generate recipe.json from the workspace # 3. backend – build the backend binary (release) # 4. frontend – build the frontend WASM bundle with Trunk # 5. runtime – minimal image: backend binary + static frontend + nginx # ============================================================ # --------------- Stage 1: Chef base --------------- FROM rust:1-bookworm AS chef RUN cargo install cargo-chef WORKDIR /app # --------------- Stage 2: Planner --------------- FROM chef AS planner COPY Cargo.toml Cargo.lock ./ COPY src/ src/ COPY backend/ backend/ COPY frontend/ frontend/ RUN cargo chef prepare --recipe-path recipe.json # --------------- Stage 3: Backend builder --------------- FROM chef AS backend-builder COPY --from=planner /app/recipe.json recipe.json RUN cargo chef cook --release --recipe-path recipe.json -p backend COPY Cargo.toml Cargo.lock ./ COPY src/ src/ COPY backend/ backend/ COPY frontend/ frontend/ RUN cargo build --release -p backend # --------------- Stage 4: Frontend builder --------------- FROM chef AS frontend-builder # Add the WASM target RUN rustup target add wasm32-unknown-unknown # Install Trunk (the WASM bundler used by the frontend) and sass (for SCSS) RUN cargo install trunk # Cache frontend dependencies COPY --from=planner /app/recipe.json recipe.json RUN cargo chef cook --release --target wasm32-unknown-unknown --recipe-path recipe.json -p frontend # Copy full workspace source for the build COPY Cargo.toml Cargo.lock ./ COPY src/ src/ COPY backend/ backend/ COPY frontend/ frontend/ # Build the frontend WASM bundle # Trunk outputs to frontend/dist by default WORKDIR /app/frontend RUN trunk build --release # --------------- Stage 5: Runtime --------------- FROM debian:bookworm-slim AS runtime # Install runtime dependencies: # - ca-certificates & libssl3: TLS for PostgreSQL connections # - nginx: serves the frontend static files and reverse-proxies /api to the backend RUN apt-get update && \ apt-get install -y --no-install-recommends ca-certificates libssl3 nginx && \ rm -rf /var/lib/apt/lists/* WORKDIR /app # Copy the compiled backend binary COPY --from=backend-builder /app/target/release/backend /app/backend # Copy migrations COPY backend/migrations/ /app/migrations/ # Copy the frontend static build output COPY --from=frontend-builder /app/frontend/dist /var/www/html # Nginx configuration: serve frontend + reverse-proxy /api to the backend RUN cat > /etc/nginx/sites-available/default <<'EOF' server { listen 80; server_name _; root /var/www/html; index index.html; # Serve static frontend files, fall back to index.html for client-side routing location / { try_files $uri $uri/ /index.html; } # Reverse-proxy API requests to the Axum backend location /api/ { proxy_pass http://127.0.0.1:8001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } EOF # Startup script: launch backend in the background, then nginx in the foreground RUN cat > /app/start.sh <<'SCRIPT' #!/bin/bash set -e # Start the backend API server in the background /app/backend & # Start nginx in the foreground (keeps the container alive) nginx -g 'daemon off;' SCRIPT RUN chmod +x /app/start.sh EXPOSE 80 # Environment variables should be provided at runtime: # DATABASE_URL – PostgreSQL connection string # TOKEN_SECRET – JWT signing key # ORIGIN – Allowed CORS origin (should be the public URL of this container) CMD ["/app/start.sh"]