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: "SnapOtter を Docker で本番環境にデプロイします。ハードウェア要件、GPU のセットアップ、Nginx、Traefik、Cloudflare 向けのリバースプロキシ設定を扱います。"
|
||||
i18n_output_hash: 2b65cb4be9d1
|
||||
i18n_source_hash: 98172965118b
|
||||
i18n_source_hash: 2a722f86da75
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: b3b304700876
|
||||
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
|
||||
```
|
||||
|
||||
`--gpus all` と NVIDIA Container Toolkit が正しく設定されているにもかかわらず、AI ツールが CPU 上で実行される場合は、**設定 → 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 ごと・1 分あたりの 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 ネットワーク上、あるいは LAN 上のリバースプロキシは初期状態で信頼されるため、レート制限、ログインのブルートフォース制限、監査ログ、enterprise 版の IP 許可リストのいずれも、設定なしで実際のクライアント IP を見ます。
|
||||
|
||||
`TRUST_PROXY=true` にするのは、前段のプロキシが**公開**アドレスから SnapOtter に到達する場合、たとえば別ネットワークにあるクラウドロードバランサーの場合だけにしてください。直接公開されたインスタンスでは、この値は `request.ip` を攻撃者の制御下に置きます。ヘッダーを次々に変える相手には、リクエストごとに新しいレート制限枠が与えられるからです。
|
||||
|
||||
クライアント IP を測る前に知っておきたいことが 2 つあります。macOS と Windows の Docker Desktop は、公開ポートをユーザーランドのプロキシ経由で提供し、送信元アドレスをすべて VM ゲートウェイ `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) にあります。
|
||||
|
||||
以下のすべてのプロキシについて 2 つのことが重要です。それは、大きなリクエスト本文 (アップロード) を許可することと、応答をバッファリングしないことです。応答バッファリング プロキシは 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