- script-src: add us-assets.i.posthog.com (TinaCMS bundles PostHog) - connect-src: add us.i.posthog.com, us-assets.i.posthog.com - frame-src: add ai-impress.com (TinaCMS visual editor iframes the site) - font-src: add data: (TinaCMS font loading) - X-Frame-Options: DENY → SAMEORIGIN (required for TinaCMS admin preview) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
70 lines
3 KiB
Nginx Configuration File
70 lines
3 KiB
Nginx Configuration File
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 https://us-assets.i.posthog.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' data: 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 https://us.i.posthog.com https://us-assets.i.posthog.com; frame-src https://www.youtube.com https://ai-impress.com; media-src 'self'; worker-src 'self' blob:;" always;
|
|
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;
|
|
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
|
|
|
# SPA fallback
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
|
|
error_page 404 /index.html;
|
|
}
|