From eb9161804e92ab64d7d44d60d17943ec3b055a0d Mon Sep 17 00:00:00 2001 From: Cory Hawkvelt Date: Sat, 4 Apr 2026 16:49:13 +1030 Subject: [PATCH] build(docker): add multi-stage Dockerfile with nginx and docker-compose Add containerization support for production deployment: - Multi-stage Dockerfile using Bun for build and nginx for serving - docker-compose.yml for container orchestration - nginx.conf with gzip compression, caching headers, and security headers --- Dockerfile | 25 +++++++++++++++++++++++++ docker-compose.yml | 15 +++++++++++++++ nginx.conf | 29 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 nginx.conf diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b89f018 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +# Build stage +FROM oven/bun:1-alpine AS builder + +WORKDIR /app + +COPY package.json bun.lockb* ./ +RUN bun install --frozen-lockfile + +COPY . . +ARG VITE_API_BASE_URL=http://localhost:5000/api/v1 +ENV VITE_API_BASE_URL=$VITE_API_BASE_URL +RUN bun run build + +# Production stage +FROM nginx:alpine AS production + +COPY --from=builder /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 8080 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:8080 || exit 1 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..da0728a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +services: + ui: + build: . + container_name: gatehouse-ui + ports: + - "8080:8080" + environment: + - VITE_API_BASE_URL=${VITE_API_BASE_URL:-http://localhost:5000/api/v1} + restart: unless-stopped + stop_grace_period: 10s + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..1fd5053 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,29 @@ +server { + listen 8080; + server_name _; + root /usr/share/nginx/html; + index index.html; + + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_proxied any; + gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml; + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + location / { + try_files $uri $uri/ /index.html; + } + + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + location = /index.html { + add_header Cache-Control "no-cache, no-store, must-revalidate"; + } +}