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
This commit is contained in:
2026-04-04 16:49:13 +10:30
parent 13e8d8f19a
commit eb9161804e
3 changed files with 69 additions and 0 deletions
+25
View File
@@ -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;"]
+15
View File
@@ -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"
+29
View File
@@ -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";
}
}