From 0064773eaae032be3e3aecbbc74992bcd0e15a8b Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 16 Dec 2025 23:34:05 +0100 Subject: [PATCH] Add Docker-based production deployment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Multi-stage Dockerfile with Node builder and nginx server - Nginx configuration with gzip, security headers, and caching - Docker Compose setup with health checks - Updated README with deployment instructions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .dockerignore | 34 ++++++++++++++++++++++++++++++++++ Dockerfile | 37 +++++++++++++++++++++++++++++++++++++ README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 24 ++++++++++++++++++++++++ nginx.conf | 31 +++++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+) create mode 100644 .dockerignore 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..6b5943f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,34 @@ +# Dependencies +node_modules +npm-debug.log* + +# Build output +dist + +# Git +.git +.gitignore + +# IDE +.vscode +.idea + +# OS files +.DS_Store +Thumbs.db + +# Environment +.env +.env.local + +# Docker +Dockerfile +docker-compose.yml +.dockerignore + +# Documentation +README.md + +# Misc +*.log +.cache diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ab62d5a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,37 @@ +# Multi-stage build for production deployment + +# Stage 1: Build the application +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm ci --only=production + +# Copy source code +COPY . . + +# Build the application +RUN npm run build + +# Stage 2: Serve with nginx +FROM nginx:alpine + +# Copy built files from builder stage +COPY --from=builder /app/dist /usr/share/nginx/html + +# Copy nginx configuration +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Expose port 80 +EXPOSE 80 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1 + +# Start nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/README.md b/README.md index 11ae4c1..4646f4b 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,48 @@ npm run build The built files will be in the `dist/` directory. +## Docker Deployment + +### Using Docker Compose (Recommended) + +```bash +# Build and start the container +docker-compose up -d + +# View logs +docker-compose logs -f + +# Stop the container +docker-compose down +``` + +The game will be available at `http://localhost:8080` + +### Using Docker directly + +```bash +# Build the image +docker build -t whalehunting-game . + +# Run the container +docker run -d -p 8080:80 --name whalehunting whalehunting-game + +# View logs +docker logs -f whalehunting + +# Stop and remove container +docker stop whalehunting +docker rm whalehunting +``` + +### Production Deployment Notes + +- The Docker image uses nginx to serve static files +- Includes gzip compression for better performance +- Health checks are configured for container monitoring +- Security headers are enabled +- Static assets are cached for 1 year + ## Project Structure ``` diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d96743f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +version: '3.8' + +services: + whalehunting-game: + build: + context: . + dockerfile: Dockerfile + image: whalehunting-game:latest + container_name: whalehunting-game + ports: + - "8080:80" + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"] + interval: 30s + timeout: 3s + retries: 3 + start_period: 5s + networks: + - whalehunting-network + +networks: + whalehunting-network: + driver: bridge diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..6cfbf33 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,31 @@ +server { + listen 80; + 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/javascript application/x-javascript application/xml+rss; + + # 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; + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Serve index.html for all routes (SPA support) + location / { + try_files $uri $uri/ /index.html; + } + + # Error pages + error_page 404 /index.html; +}