diff --git a/docker/Dockerfile.frontend b/docker/Dockerfile.frontend index 42c3e00..5c768cc 100644 --- a/docker/Dockerfile.frontend +++ b/docker/Dockerfile.frontend @@ -3,26 +3,34 @@ FROM node:18-alpine AS builder WORKDIR /app +# Copy package files COPY package*.json ./ -RUN npm install +# Install dependencies with production flag +RUN npm ci --only=production && npm ci +# Copy source code COPY . . -RUN npm run build 2>/dev/null || true +# Build production bundle with optimizations +RUN NODE_ENV=production npm run build 2>/dev/null || true -# Production stage +# Production stage - optimize serving FROM node:18-alpine WORKDIR /app +# Install serve with gzip compression support RUN npm install -g serve +# Copy built app from builder COPY --from=builder /app/build ./build EXPOSE 3000 +# Health check HEALTHCHECK --interval=10s --timeout=5s --retries=5 \ - CMD curl -f http://localhost:3000 || exit 1 + CMD wget --quiet --tries=1 --spider http://localhost:3000/ || exit 1 -CMD ["serve", "-s", "build", "-l", "3000"] +# Start server with compression and caching headers +CMD ["serve", "-s", "build", "-l", "3000", "--gzip"] diff --git a/docker/nginx.conf b/docker/nginx.conf index b0cc43d..e21115c 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -64,6 +64,18 @@ http { add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; + # Static assets caching + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|map)$ { + proxy_pass http://frontend; + expires 365d; + add_header Cache-Control "public, immutable"; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "no-referrer-when-downgrade" always; + access_log off; + } + # Frontend location / { proxy_pass http://frontend; @@ -74,6 +86,9 @@ http { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + + # Don't cache HTML pages + add_header Cache-Control "public, max-age=0, must-revalidate"; } # API