# --- Build stage --- FROM rust:1.88-alpine AS builder RUN apk add --no-cache musl-dev pkgconfig openssl-dev WORKDIR /app COPY Cargo.toml Cargo.lock* ./ # Pre-fetch deps with a dummy build for layer caching RUN mkdir src && echo "fn main(){}" > src/main.rs && \ cargo build --release && \ rm -rf src COPY src ./src COPY static ./static COPY migrations ./migrations RUN touch src/main.rs && cargo build --release # --- Runtime stage --- FROM alpine:3.21 # Run as an unprivileged user (defense-in-depth). The media volume mounts at # /media; creating it here as `app` means a fresh named volume inherits app # ownership and is writable without running as root. (An existing root-owned # volume from a prior deploy needs a one-time `chown -R app:app` — see deploy notes.) RUN apk add --no-cache ca-certificates ffmpeg \ && addgroup -S app && adduser -S -G app app \ && mkdir -p /media && chown app:app /media WORKDIR /app COPY --from=builder /app/target/release/eventsnap-backend ./ RUN chown -R app:app /app USER app EXPOSE 3000 CMD ["./eventsnap-backend"]