server { listen 80; server_name localhost; # Allow larger uploads (default is 1MB) – must be >= backend MAX_UPLOAD_SIZE client_max_body_size 50m; # Enable gzip compression for text-based assets gzip on; gzip_vary on; gzip_min_length 1024; gzip_comp_level 6; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/atom+xml image/svg+xml text/html; gzip_disable "msie6"; gzip_proxied any; # Static assets with aggressive caching location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ { root /usr/share/nginx/html; expires 1y; add_header Cache-Control "public, immutable"; access_log off; } location ~* \.(css|js)$ { root /usr/share/nginx/html; expires 1y; add_header Cache-Control "public, immutable"; access_log off; } location ~* \.(woff|woff2|ttf|eot)$ { root /usr/share/nginx/html; expires 1y; add_header Cache-Control "public, immutable"; access_log off; } # SEO files - proxy to backend for dynamic generation location = /robots.txt { proxy_pass http://backend:8080; proxy_http_version 1.1; proxy_set_header Host $host; 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; proxy_cache_bypass $http_cache_control; add_header Cache-Control "public, max-age=3600"; } location = /sitemap.xml { proxy_pass http://backend:8080; proxy_http_version 1.1; proxy_set_header Host $host; 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; proxy_cache_bypass $http_cache_control; add_header Cache-Control "public, max-age=3600"; } location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; # Cache HTML files for shorter period add_header Cache-Control "public, max-age=3600, must-revalidate"; } # API proxy with compression location /api/ { proxy_pass http://backend:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Accept-Encoding gzip; # Ensure Nginx accepts large uploads on this route as well client_max_body_size 50m; # Enable buffering for better performance proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 8 4k; proxy_busy_buffers_size 8k; } # Short links and tracked redirect - must bypass SPA and hit backend location ^~ /s/ { proxy_pass http://backend:8080; proxy_http_version 1.1; proxy_set_header Host $host; 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; } location = /r { proxy_pass http://backend:8080; proxy_http_version 1.1; proxy_set_header Host $host; 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; } # Proxy backend-served assets so the frontend can use relative URLs location /uploads/ { proxy_pass http://backend:8080; proxy_http_version 1.1; proxy_set_header Host $host; 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; # Allow long cache; backend may set ETag/Last-Modified add_header Cache-Control "public, max-age=2592000"; } location /dist/ { proxy_pass http://backend:8080; proxy_http_version 1.1; proxy_set_header Host $host; 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; add_header Cache-Control "public, max-age=2592000"; } location /cache/ { proxy_pass http://backend:8080; proxy_http_version 1.1; proxy_set_header Host $host; 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; add_header Cache-Control "public, max-age=600"; } # Error pages error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }