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.
8.3 KiB
i18n_source_hash, i18n_provenance, i18n_output_hash, i18n_hash_version
| i18n_source_hash | i18n_provenance | i18n_output_hash | i18n_hash_version |
|---|---|---|---|
| 521c03a6416c | machine | 858d5bec009c | 2 |
低リソース環境のセットアップ
SnapOtter は小さなハードウェアでも快適に動作します。Raspberry Pi 4 や 5、古いラップトップ、2 GB の VPS などです。このページはそうしたマシンのための実践ガイドです。何が期待できるか、無理のない上限を設定したコピー&ペーストで使えるセットアップ、そしてどの機能を見送るべきかを扱います。これらの数値の裏付けとなる完全なベンチマークデータは ハードウェア要件 にあります。
まず、2 つの厳しい制約があります。
- 64 ビットのみ。 イメージは
linux/amd64とlinux/arm64向けにビルドされています。32 ビット ARM(armv7/armhf)はサポートされないため、初代 Pi と Pi Zero ファミリーは対象外です。 - メモリの下限は 2 GB。 512 MB ではスタックを起動できず、1 GB では複数ファイルのバッチで失敗します。2 コアと 2 GB が、余裕を持って動作する最小構成です。
小さなハードウェアで快適に動くもの
AI 以外のすべてのツールは 2 GB / 2 コアのマシンで動作します。画像とファイルのセクション全体、PDF ツール、そしてストリームコピーのビデオ・オーディオ操作(トリミング、ミュート、コンテナのリマックス)です。ほとんどは 1 秒未満で完了します。
例外となるワークロードは 2 つです。
- ビデオの再エンコード(コーデック間の変換)は CPU に依存します。高速なデスクトップ CPU で約 40 秒かかる 1080p のクリップは、Pi クラスの CPU では数分かかることがあります。ストリームコピーの操作は引き続き一瞬で終わります。
- AI ツールには RAM(4 GB 推奨)とディスク(大きなバンドルは 1 つあたり 4〜5 GB)が必要で、重いもの(アップスケーリング、写真の復元、背景除去)は Pi クラスの CPU では現実的ではありません。顔検出や OCR のような軽い AI は、そのためのメモリがあれば利用できます。
どちらも使わない限りインストールも実行もされません。AI バンドルを何もインストールしていなければアプリはアイドル時に約 360 MB で動作し、AI バンドルは管理者が有効化したときにのみダウンロードされます。
Raspberry Pi / 古いラップトップでの手順
これは はじめに の標準的な Compose インストールに、リソース制限と控えめな上限を加えたものです。64 ビット OS を前提としています(Pi の場合: Raspberry Pi OS 64-bit または Ubuntu Server arm64)。
services:
snapotter:
image: snapotter/snapotter:latest
ports:
- "1349:1349"
volumes:
- ./snapotter-data:/data
environment:
- DATABASE_URL=postgres://snapotter:snapotter@db:5432/snapotter
- REDIS_URL=redis://redis:6379
# Small-box profile: see the table below for what each cap does.
- CONCURRENT_JOBS=1
- MAX_WORKER_THREADS=2
- MAX_BATCH_SIZE=5
- MAX_UPLOAD_SIZE_MB=100
- MAX_MEGAPIXELS=50
- MAX_VIDEO_DURATION_S=300
deploy:
resources:
limits:
cpus: "2"
memory: 2G
depends_on:
- db
- redis
restart: unless-stopped
db:
image: postgres:17-alpine
environment:
- POSTGRES_USER=snapotter
- POSTGRES_PASSWORD=snapotter # 非ローカル展開の場合はこれを変更します
- POSTGRES_DB=snapotter
volumes:
- ./postgres-data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:8-alpine
command: redis-server --maxmemory 256mb --maxmemory-policy noeviction
restart: unless-stopped
Pi クラスのマシン向けの注意点:
- データボリュームと Postgres には SD カードより USB SSD を優先してください。 ジョブのワークスペースは実際にディスク IO を行い、SD カードは遅いうえに摩耗も早いためです。
- オールインワンの単一コンテナもここで動作します(
DATABASE_URL/REDIS_URLが未設定のときに組み込みの Postgres と Redis が使われます)。メモリに余裕のないホストでは、REDIS_MAXMEMORYで組み込み Redis の上限を下げてください(設定 を参照)。Compose のほうがサービスごとの細かい制御ができるため、この手順では Compose を使っています。 - 2 GB のデバイスにはスワップを追加してください。 時折のスパイク(大きな PDF、上限をかけ忘れたバッチ)がアウトオブメモリのキルで終わるのを防ぎます。zram は SD カードにやさしい選択肢です。
- arm64 イメージは CPU のみです。ARM ボードに CUDA はありません。
チューニング項目
上限はすべて環境変数で、設定 に完全なドキュメントがあります。0 は無制限または自動を意味します。小さなハードウェアで重要なのは次のとおりです。
| 変数 | 小型マシンでの推奨値 | 何を守るか |
|---|---|---|
CONCURRENT_JOBS |
1 |
並列で実行されるジョブの数。自動検出は CPU コア数マイナス 1 を使います。大きなマシンでは適切ですが、メモリが厳しい 2 コアのマシンには積極的すぎます。 |
MAX_WORKER_THREADS |
2 |
画像処理のスレッドプール。 |
MAX_BATCH_SIZE |
5 |
1〜2 GB のマシンが最初にメモリ不足に陥るのはバッチです。 |
MAX_UPLOAD_SIZE_MB |
100 |
1 つの巨大なファイルがワークスペース全体を占有するのを防ぎます。 |
MAX_MEGAPIXELS |
50 |
100 MP 超の画像のデコードは、ファイルサイズに関係なく RAM を消費します。 |
MAX_VIDEO_DURATION_S |
300 |
長いトランスコードは、小さな CPU を数分から数時間占有します。 |
PROCESSING_TIMEOUT_S |
600 |
暴走したジョブでも最終的にはマシンを解放させるための強制的な上限です。 |
これらの上限はサーバーが受け付けるものに適用されるため、できるだけ小さくするのではなく、実際の用途に合わせて設定してください。ビデオをまったく扱わないなら MAX_VIDEO_DURATION_S の上限にコストはありません。毎日ドキュメントをスキャンするなら、MAX_PDF_PAGES に上限をかけないでください。
見送るべきもの
- 重い AI バンドル。 アップスケーリング、写真の復元、背景除去は GPU か高速なメニーコア CPU を必要とし、各バンドルはディスクを 4〜5 GB 消費します。小さなマシンでは、そもそもインストールしないでください。バンドルがないツールは、実行される代わりにインストールを促す画面を表示します。
- 日常的なワークロードとしてのビデオ再エンコード。 時折のトランスコードは問題ありません(単に遅いだけです)。継続的なトランスコードのキューに必要なのは CPU コアであって、Pi ではありません。
- 使わないツール全般。 管理者は Settings で個々のツールを無効にでき、無効にしたツールは UI から消え、その API ルートも登録されなくなります。それ自体でメモリが節約されるわけではありませんが、共有の小さなインスタンスが、ハードウェアには耐えられない唯一のワークロードのために使われてしまうのを防げます。
後でインスタンスをより大きなハードウェアに移す場合は、上限を外せば(0 に戻せば)、同じデータボリュームをそのまま引き継げます。