# SciLit 生产环境 Nginx 配置 # HTTPS 应由上游反向代理(Caddy / Nginx / LB)终止,本配置仅处理 HTTP。 # 上游代理需设置 X-Forwarded-Proto 和 X-Forwarded-For 以便后端正确处理。 # ── Docker DNS 解析(backend 容器重建后自动刷新)────────────── # proxy_pass 必须用变量形式触发动态解析,固定字符串会在启动时缓存 resolver 127.0.0.11 ipv6=off valid=30s; # ── Gzip ────────────────────────────────────────────────────────── gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 5; gzip_min_length 256; gzip_types text/plain text/css text/javascript application/javascript application/json application/xml image/svg+xml font/woff2; # ── 文件上传大小 ────────────────────────────────────────────────── client_max_body_size 20m; # ── 日志格式 ────────────────────────────────────────────────────── log_format json escape=json '{' '"time":"$time_iso8601",' '"remote":"$remote_addr",' '"host":"$host",' '"method":"$request_method",' '"path":"$uri",' '"status":$status,' '"size":$body_bytes_sent,' '"referer":"$http_referer",' '"ua":"$http_user_agent",' '"upstream":"$upstream_addr",' '"request_time":"$request_time"' '}'; access_log /var/log/nginx/access.log json; error_log /var/log/nginx/error.log warn; server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; # ── 安全响应头 ──────────────────────────────────────────────── add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY; add_header X-XSS-Protection "0"; add_header Referrer-Policy strict-origin-when-cross-origin; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'" always; # ── SPA 入口(无 hash 的路径)───────────────────────────────── location / { try_files $uri $uri/ /index.html; # index.html 不缓存 add_header Cache-Control "no-cache, no-store, must-revalidate"; } # ── 含 hash 的静态资源(vite 输出格式 *.xxx.hash.js/css) ──── location ~* \.(js|css|svg|woff2?)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; # 不匹配 hash 的后备 try_files $uri /index.html; } # ── 图片 / 字体 ────────────────────────────────────────────── location ~* \.(png|jpg|jpeg|gif|ico|webp|woff2?|ttf|eot)$ { expires 30d; add_header Cache-Control "public, immutable"; access_log off; } # ── API 代理(用变量触发动态 DNS 解析)───────────────────────── set $backend_upstream http://backend:8000; location /api/ { proxy_pass $backend_upstream; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; 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_read_timeout 60s; proxy_send_timeout 60s; } # ── WS 升级(长连接,超时更长)─────────────────────────────── location /api/v1/ws/ { proxy_pass $backend_upstream; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; 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_read_timeout 3600s; proxy_send_timeout 60s; } # ── /health 不记日志 ──────────────────────────────────────── location /health { proxy_pass $backend_upstream; access_log off; proxy_http_version 1.1; } }