server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; # Enable gzip compression gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json; # Cache static assets (Vite hashed filenames) location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; } # Blog JSON/images - short cache for frequent updates location /blog/ { expires 10m; add_header Cache-Control "public, must-revalidate"; try_files $uri /index.html; } # Chatbot API proxy location /api/chat { resolver 127.0.0.11 valid=30s; set $chatbot_api http://aimpress-chatbot-api:8000; proxy_pass $chatbot_api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Content-Type $http_content_type; proxy_buffering off; } # API proxy to email service (resolver allows nginx to start even if email-api is down) location /api/ { resolver 127.0.0.11 valid=30s; set $email_api http://aimpress-email-api:3001; proxy_pass $email_api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Content-Type $http_content_type; } # SEO headers add_header X-Robots-Tag "index, follow" always; # Reviews JSON - short cache location = /reviews.json { expires 1h; add_header Cache-Control "public, must-revalidate"; } # Security headers add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://cdn.mxpnl.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https://lh3.googleusercontent.com https://www.googletagmanager.com; connect-src 'self' https://www.google-analytics.com https://analytics.google.com https://*.google-analytics.com https://*.analytics.google.com https://api-js.mixpanel.com https://api.mixpanel.com https://*.mixpanel.com https://*.mxpnl.com https://*.amplitude.com https://content.tinajs.io https://*.tinajs.io https://api.tinajs.io; frame-src https://www.youtube.com; media-src 'self'; worker-src 'self' blob:;" always; add_header X-Frame-Options "DENY" 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; add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; # SPA fallback location / { try_files $uri $uri/ /index.html; } error_page 404 /index.html; }