diff --git a/docker/nginx.stage.conf b/docker/nginx.stage.conf index ed3a75b..0ea8cbc 100644 --- a/docker/nginx.stage.conf +++ b/docker/nginx.stage.conf @@ -228,6 +228,44 @@ server { add_header Referrer-Policy "strict-origin-when-cross-origin" always; } + # ============================================================ + # /preset-models/* → api-server :3721 (B8 預設模型 .nef 公用下載) + # + # 7 個系統預設模型 .nef 由 api-server 直接讀 image 內 /app/assets/preset-models + # 串流(GET /preset-models/{id}.nef,不簽 token、preset 公用)。 + # + # ⚠️ 為什麼必須有這條 location: + # 下方 catch-all `location /` 反代到 Next.js frontend (:3000)。若沒有這條, + # /preset-models/* 會落到 frontend → Next 沒有此 route → 404,preset 下載斷掉。 + # 必須在 catch-all 之前用前綴 location 攔下來,導到 api-server。 + # + # 比照 /storage/ pattern(同為 api-server 大檔下載端點): + # - proxy_buffering off:.nef 1-13MB 二進位,串流直送、不在 nginx 全 buffer 後才回 + # - X-Forwarded-Proto https:backend 組對外 absolute URL 時判斷正確 + # - server-level client_max_body_size 100M 是「上傳」上限,對下載無影響 + # - cache:preset 公用、內容固定(baked 進 image,id 對應檔不變)→ 允許瀏覽器 + # 快取 1 天減少重複下載大檔;非用戶私有資料、無 PII,不需 no-store。 + # ============================================================ + location /preset-models/ { + proxy_pass http://visiona_api; + proxy_http_version 1.1; + proxy_buffering off; + + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Connection ""; + + # preset 公用、內容固定 → 可被瀏覽器快取(非敏感、非用戶私有) + expires 1d; + add_header Cache-Control "public, max-age=86400" always; + + # nginx location level 的 add_header 會完全覆蓋 server level — re-add 安全 header + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + } + # ============================================================ # /tunnel/connect — WebSocket upgrade,由 visionA Agent 連入 # 要 long-lived(24h 心跳級別);拉到 86400s。