From bdb1b75f3671ec66099507af58949a4081a792e4 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:09:13 +0000 Subject: [PATCH] Add Docker Compose configuration --- .dockerignore | 13 +++++++++++++ .env.example | 2 ++ Dockerfile | 34 ++++++++++++++++++++++++++++++++++ docker-compose.yml | 24 ++++++++++++++++++++++++ nginx.conf | 29 +++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e9ab1c8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +node_modules +dist +.git +.gitignore +*.md +.env +.env.local +.vscode +.idea +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4c3cb04 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +# Timezone +TZ=Europe/Copenhagen diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..228006c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm ci + +# Copy source files +COPY . . + +# Build the app +RUN npm run build + +# Production stage +FROM nginx:alpine + +# Copy built files to nginx +COPY --from=builder /app/dist /usr/share/nginx/html + +# Copy nginx configuration +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Expose port +EXPOSE 8080 + +# Health check +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..7d362a6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +version: '3.8' + +services: + docker-webui: + build: + context: . + dockerfile: Dockerfile + container_name: docker-webui + ports: + - "8080:8080" + environment: + - TZ=${TZ:-Europe/Copenhagen} + volumes: + # Mount Docker socket for container management (read-only for safety) + - /var/run/docker.sock:/var/run/docker.sock:ro + # Mount proc for host metrics (read-only) + - /proc:/host/proc:ro + restart: unless-stopped + networks: + - docker-webui-network + +networks: + docker-webui-network: + driver: bridge diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..215d269 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,29 @@ +server { + listen 8080; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # SPA fallback - serve index.html for all routes + location / { + try_files $uri $uri/ /index.html; + } + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } +}