{ email {$CADDY_EMAIL} } # 反代到后端时,用 Caddy 实测到的对端地址覆盖 X-Real-IP, # 防止客户端伪造 X-Forwarded-For 影响限流、审计和支付下单的 client_ip。 (backend_proxy) { header_up X-Real-IP {remote_host} } {$CADDY_DOMAIN} { encode zstd gzip header { Strict-Transport-Security "max-age=31536000" X-Content-Type-Options "nosniff" X-Frame-Options "DENY" Referrer-Policy "strict-origin-when-cross-origin" Permissions-Policy "camera=(), microphone=(), geolocation=()" Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data: blob:; font-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self'" } # 聊天 SSE 长连接:关闭缓冲,逐条推送。 @api_sse { path /api/chats/events /api/admin/chats/events } handle @api_sse { reverse_proxy backend:8080 { flush_interval -1 import backend_proxy } } handle /api/* { # 后端上传上限 10MB,这里前置拦掉超大请求体(留 1MB 余量)。 request_body { max_size 11MB } reverse_proxy backend:8080 { import backend_proxy } } handle /health { reverse_proxy backend:8080 { import backend_proxy } } # 生产后台页面使用构建时配置的隐藏入口,旧 /admin 入口直接返回 404。 @legacy_admin path /admin /admin/* handle @legacy_admin { respond 404 } # 其余流量返回前端静态资源,未命中的路径交给 SPA 处理。 handle { root * /srv/dist try_files {path} /index.html file_server } }