mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: release QA hardening across processing, media, security, and CI gates (#649)
A release-readiness QA pass over the whole product. The commits split into defects a user would hit and gates that were reporting green while measuring nothing. ## Fixes that change behaviour Rate limiting was bypassable on every install: TRUST_PROXY defaulted to true, so request.ip came from a client-set header and a forged X-Forwarded-For got past the login limiter. The default is now a private-network trust list. A transient Postgres outage stranded in-flight jobs, leaving finished output on disk with no row pointing at it. A reconciler now resolves those rows and adopts the bytes rather than dropping the work. A Redis connection that moved to a new address wedged every read-blocked consumer, so completions stopped signalling while health still answered 200. Socket timeouts plus subscriber pings recover it. Installing more than one AI bundle left the shared venv multi-versioned and silently broke three tools. The installer now reconciles distributions to one version each. Converting an image to JXL at quality 1 through 4 returned a 500, because libjxl 0.7 rejects the distance those values compute. The quality is floored at what the encoder honours. A missing ffmpeg was also reported to the user as a corrupt upload; it now says the engine is unavailable. RAW uploads reached an unpatched LibRaw on arm64, so it is built from source at 0.22.2, and the release scan was split so it can fail on an unfixed critical instead of hiding it behind ignore-unfixed. ## Gates that could not fail Two mutation lanes ran zero mutants because Stryker crawled the gitignored docs build; coverage discarded its whole report on any failing test; the lint gate skipped root tests, scripts, and two workspaces; and several generated matrices counted a host missing ffmpeg as a passing tool. Each now measures what it claims. Full evidence and the outstanding release items are tracked locally and are not part of this branch.
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "使用 Docker 將 SnapOtter 部署到正式環境。硬體需求、GPU 設定,以及 Nginx、Traefik 和 Cloudflare 的反向代理設定。"
|
||||
i18n_output_hash: d1dc1e293c3a
|
||||
i18n_source_hash: 98172965118b
|
||||
i18n_source_hash: 2a722f86da75
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 97aa47ef2602
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# 部署 {#deployment}
|
||||
@@ -47,7 +48,7 @@ services:
|
||||
# - MAX_USERS=0 # Max user accounts
|
||||
|
||||
# --- Networking ---
|
||||
# - TRUST_PROXY=true # Trust X-Forwarded-For headers (set false if not behind a proxy)
|
||||
# - TRUST_PROXY=loopback,linklocal,uniquelocal # Which peers may set the client IP via X-Forwarded-For (default shown)
|
||||
|
||||
# --- Bind mount permissions ---
|
||||
# - PUID=1000 # Match your host user's UID (run: id -u)
|
||||
@@ -82,7 +83,7 @@ services:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter -d snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
@@ -170,13 +171,13 @@ services:
|
||||
container_name: SnapOtter-postgres
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_PASSWORD: snapotter # 針對非本地部署更改此設置
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter -d snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
@@ -207,13 +208,17 @@ volumes:
|
||||
docker compose -f docker-compose-gpu.yml up -d
|
||||
```
|
||||
|
||||
在記錄中確認 CUDA 是否偵測到:
|
||||
### 驗證 GPU 加速 {#verify-gpu-acceleration}
|
||||
|
||||
檢查日誌中的 CUDA 檢測:
|
||||
|
||||
```bash
|
||||
docker logs SnapOtter 2>&1 | head -20
|
||||
# Look for: [gpu] CUDA available via torch
|
||||
```
|
||||
|
||||
如果 AI 工具在 CPU 上運行,即使 `--gpus all` 和 NVIDIA Container Toolkit 設定正確,請從 **設定 → AI 功能** 重新安裝受影響的捆綁包(例如背景刪除)。安裝程式會恢復 ONNX 運行時的 GPU 版本,而由另一個捆綁包(例如轉錄)引入的僅 CPU 版本可能會在共享 AI 環境中隱藏。如果從 UI 重新安裝無法恢復舊映像上的 GPU,請參閱 [問題 #490](https://github.com/snapotter-hq/SnapOtter/issues/490) 中的手動修復。
|
||||
|
||||
## 硬體需求 {#hardware-requirements}
|
||||
|
||||
這些數字來自跨多種系統的效能測試,從搭載 NVIDIA RTX 4070 的現代 amd64 工作站,一直到 Raspberry Pi,在每台機器上執行整個工具目錄,並掃描 Docker 資源限制以找出實際的下限。
|
||||
@@ -436,11 +441,11 @@ securityContext:
|
||||
| `AUTH_ENABLED` | `true` | 啟用/停用登入需求 |
|
||||
| `DEFAULT_USERNAME` | `admin` | 初始管理員使用者名稱 |
|
||||
| `DEFAULT_PASSWORD` | `admin` | 初始管理員密碼(首次登入時強制變更) |
|
||||
| `MAX_UPLOAD_SIZE_MB` | `100` | 每個檔案的上傳限制 |
|
||||
| `MAX_BATCH_SIZE` | `100` | 每個批次請求的最大檔案數 |
|
||||
| `MAX_UPLOAD_SIZE_MB` | `0`(無限制) | 每個檔案的上傳限制(MB)。映像檔出廠即為 `0`;從原始碼建置則從 100 起 |
|
||||
| `MAX_BATCH_SIZE` | `0`(無限制) | 每個批次請求的最大檔案數。映像檔出廠即為 `0`;從原始碼建置則從 100 起 |
|
||||
| `RATE_LIMIT_PER_MIN` | `1000` | 每個 IP 每分鐘的 API 請求數(設為 0 以停用) |
|
||||
| `MAX_USERS` | `0`(無限制) | 最大使用者帳號數 |
|
||||
| `TRUST_PROXY` | `true` | 信任來自反向代理的 X-Forwarded-For 標頭 |
|
||||
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | 允許哪些對端透過 `X-Forwarded-For` 設定用戶端 IP。預設僅限私有網路 |
|
||||
| `PUID` | `999` | 以此 UID 執行(用於繫結掛載權限) |
|
||||
| `PGID` | `999` | 以此 GID 執行(用於繫結掛載權限) |
|
||||
| `LOG_LEVEL` | `info` | 記錄詳細程度:fatal、error、warn、info、debug、trace |
|
||||
@@ -483,7 +488,13 @@ curl http://localhost:1349/api/v1/health
|
||||
|
||||
## 反向代理 {#reverse-proxy}
|
||||
|
||||
SnapOtter 預設會設定 `TRUST_PROXY=true`,使速率限制與記錄使用來自 `X-Forwarded-For` 標頭的真實用戶端 IP。
|
||||
`TRUST_PROXY` 預設為 `loopback,linklocal,uniquelocal`,因此 SnapOtter 只相信來自私有網路對端的 `X-Forwarded-For`。同一主機、Docker 網路或區域網路中的反向代理開箱即受信任,這表示速率限制、登入暴力破解限制、稽核記錄以及 enterprise 版的 IP 允許清單,都不必設定就能看到真實的用戶端 IP。
|
||||
|
||||
只有當前置代理從**公開**位址連到 SnapOtter 時才設為 `TRUST_PROXY=true`,例如位於另一個網路的雲端負載平衡器。在直接曝露的執行個體上,這個值會讓 `request.ip` 落入攻擊者手中,因為不斷更換該標頭的呼叫端每次請求都能拿到全新的速率限制計數。
|
||||
|
||||
動手量測用戶端 IP 之前,有兩件事要知道。macOS 與 Windows 上的 Docker Desktop 透過使用者空間代理提供已發布的連接埠,會把所有來源位址改寫成虛擬機閘道 `192.168.65.1`,因此在那裡無論 `TRUST_PROXY` 設成什麼都拿不回真實用戶端;面向網際網路的部署請放在 Linux 上。而且在任何平台上,經由 `localhost` 連到已發布的連接埠都會被視為橋接閘道而非你的用戶端,所以 localhost 測試完全說明不了真實用戶端是如何歸屬的。`TRUST_PROXY` 各種取值的完整表格與 Docker Desktop 注意事項請見 [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md#client-ip-resolution-trust_proxy)。
|
||||
|
||||
對於下面的每個代理來說,有兩件事很重要:允許大型請求正文(上傳),並且不緩衝回應。響應緩衝代理會破壞 SSE 進度,更明顯的是,使大文件下載“開始但永遠不會完成”,因為代理在傳遞之前保存整個文件。 SnapOtter 在下載時發送 `X-Accel-Buffering: no`,因此即使在其他地方保留緩衝,nginx 也會對它們進行串流傳輸,但除 nginx 之外的代理需要明確停用回應緩衝(如下面的每個配置所示)。如果下載中途停止,首先要檢查前面的緩衝代理。
|
||||
|
||||
### Nginx {#nginx}
|
||||
|
||||
@@ -505,7 +516,7 @@ server {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# SSE support (batch progress, feature install progress)
|
||||
# 串流響應而不是緩衝:SSE 進度(批次、AI、功能安裝)和大檔案下載需要。
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
@@ -549,7 +560,7 @@ images.example.com {
|
||||
}
|
||||
```
|
||||
|
||||
`flush_interval -1` 會停用回應緩衝,這是 SSE 進度事件(批次處理、AI 工具、功能安裝)所必需的。延長的逾時允許大型檔案上傳在 Caddy 提早關閉連線之前完成。
|
||||
`flush_interval -1` 停用回應緩衝,這是 SSE 進度事件(批次、AI 工具、功能安裝)以及大檔案下載串流(而不是停滯)所必需的。延長的逾時允許完成大檔案上傳,而無需 Caddy 提前關閉連線。
|
||||
|
||||
### Cloudflare Tunnels {#cloudflare-tunnels}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user