VPSでopen-krittをセルフホストする方法と注意点
open-krittをVPSで安全に運用するDocker Compose設定を解説します。releaseの固定、port 5173のSSH tunnel、初回scan前に設定するprovider budget、Docker socketの危険性を確認できます。
VPS で open-kritt をセルフホストし、ノート PC では運用しない理由
破棄して再構築できるサーバーで open-kritt をセルフホストします。このツールは、root として使い捨てのジョブコンテナ内で分析エージェントを実行し、各エージェントにコードの書き込み可能なコピーとインターネットへの直接アクセスを与え、エンジンサービスにホストの Docker socket をマウントします。ジョブ専用のホストであれば、これは許容できるトレードオフです。SSH keys を保管しているマシンでは危険です。
この方針を決める default setup の特性は 4 つあります。いずれもプロジェクト自身の README と compose file に記載されています。
エージェントには強い権限が想定されています。 README には、tool-enabled agents が使い捨てのジョブコンテナ内で root として実行され、書き込み可能な repository のコピーとインターネットへの直接アクセスを持つため、ツールのインストール、対象のコンパイル、テストの実行、概念実証の作成ができると記載されています。スキャンは、ファイルを読むだけの linter ではありません。依頼した任意のコード実行です。このインターネットアクセスには両面があります。エージェントが対象を調査する際に取得するものは、prompt 内に入る信頼できないテキストです。これは、エージェントに 専用の Web 検索を実行させる場合と同じ種類の露出です。
エンジンは Docker socket を保持します。 docker-compose.yml は、ホストの Docker socket を engine service にマウントします。エンジンはジョブごとに 1 つの scan container を構築して起動するためです。その socket に到達できるプロセスは、ホストの filesystem をマウントした container を起動できます。したがって、エンジンは実質的に、実行先ホスト上で root と同等の権限を持ちます。
ログイン画面がありません。 backend には application authentication が付属していません。port にアクセスできることは、調査結果と provider credit にアクセスできることを意味します。
スキャンするコードは、あなたの所有物とは限りません。 エージェントを third-party repository に向けると、その repository の build が、root としてネットワークアクセスを持つあなたのマシン上で実行されます。
coding agents を使い捨ての VM に置く理由を読んだことがあれば、これは同じ threat model であり、さらに強化されたものだと分かります。open-kritt には他の用途が何もない VPS を割り当て、root ではなく 別の最小権限 user account からその VPS を操作します。
open-kritt の実際の動作
open-kritt(リポジトリは Kritt-ai/open-kritt、ライセンスは AGPL-3.0)は、脆弱性調査を小さなタスクに分割し、それらを複数の AI エージェントで並列実行します。その後、結果の重複を排除し、優先順位を付けます。ワークフローは、目的を絞ったプロンプトを連結したものとして定義します。各ステップは、前のステップから構造化されたコンテキストを受け取ります。スキャン対象は、リモートまたはローカルの git リポジトリです。解析エンジンには Codex または Claude Code を使用します。候補が見つかった後、オプションの post-script で検証や proof of concept の作成を試行できます。
最終的に得られるのは、優先順位を付けた候補の一覧です。これはレポートではなく、トリアージ用のキューとして扱ってください。
開始前に必要なもの
- Ubuntu 24.04、Debian 12、または Rocky Linux 9 を実行する VPS。インストール手順では、x86_64 と ARM64 の両方で、これらをテスト済みディストリビューションとして記載しています。
- Compose plugin を含む Docker Engine。
- ホスト上の Node.js 20 以降。
./krittCLI はコンテナ内ではなくホスト上で実行されるためです。 - いずれか1つのモデルプロバイダー。Codex login、
OPENAI_API_KEY、CODEX_API_KEY、ANTHROPIC_API_KEY、またはOPENROUTER_API_KEY。 - プライベートリポジトリをスキャンする場合のみ
GITHUB_TOKEN。提供される.env.exampleには明記されています。GitHub token だけではスキャンを実行できません。
Docker と Node 20 を先にインストールする
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER新しいグループメンバーシップを適用するため、ログアウトしてから再度ログインします。その後、Compose プラグインが存在することを確認します。
docker compose versionバージョン文字列が表示される場合、Compose はプラグインとしてインストールされています。docker: 'compose' is not a docker command が表示される場合は、代わりに古いスタンドアロンの docker-compose バイナリが使われており、open-kritt は docker compose を呼び出します。docker グループのメンバーシップはホスト上の root と同等の権限を持つため、追加するのは open-kritt を実行するアカウントだけにしてください。この設定の詳しい手順については、VPS で Docker を実行するを参照してください。
Ubuntu 24.04 の独自リポジトリには Node 18 が含まれていますが、CLI は 20 未満のバージョンでは終了します。NodeSource を使用してください。
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node -vnode -v は v20. 以上を出力する必要があります。Rocky Linux 9 では、同等の手順として sudo dnf module enable nodejs:20 -y に続けて sudo dnf install -y nodejs を実行します。
open-kritt をクローンし、タグ付きリリースに固定する
git clone https://github.com/Kritt-ai/open-kritt
cd open-kritt
git fetch --tags
git tag --list
git checkout v1.3.0main は更新されます。タグは更新されません。2026 年 8 月時点で最新のタグは v1.3.0 です。これは 2026 年 8 月 4 日に公開されました。git tag --list を実行すると、クローン時点で存在する内容を確認できます。タグをチェックアウトすると、リポジトリは detached HEAD 状態になります。ここではこれが正しい状態です。このクローンは、コミットを続けるブランチではなく、特定のリリースに固定したデプロイとして扱うためです。後でアップグレードする場合は、リリースノートを確認してから git fetch --tags を実行し、新しいタグをチェックアウトしたうえで、./kritt start を再度実行します。start がイメージを再ビルドするためです。
sudo とともに ./kritt を実行しないでください。ドキュメントにも明記されています。CLI は .data/ 配下にプロジェクト固有の認証情報ディレクトリを管理します。そのため root として実行すると、これらのディレクトリの所有者が root になり、次回の通常ユーザーによる実行で書き込めなくなります。
./kritt setup でモデルアクセスを設定する
./kritt setupこのコマンドは、存在しない場合に .env.example から .env を作成し、各認証情報の状態を表示して、設定または解除できるようにします。値をターミナルに出力することはありません。.env とエンジンの認証情報ファイルは、いずれもモード 0600 で書き込まれます。
手動で設定する場合は、次のようにします。
cp .env.example .env
chmod 600 .env
mkdir -p .data/codex
chmod 700 .data/codex次に、プロバイダーキーを .env に入力し、ファイルのモードを 0600 のままにします。どちらの方法でも、そのサーバーには使用可能なプロバイダー認証情報が保存されます。そのため、このサーバーには他のものを置かないことが重要です。このプロジェクト専用のキーを作成してください。後でそのキーを失効させても、必要なものに影響しません。AI エージェントの手が届かない場所に Secret を保管するでは、この運用上の習慣について詳しく説明しています。
最初のスキャン前にプロバイダーの利用上限を設定する
open-kritt は処理を分散して実行するように設計されており、料金が発生するのはこの分散実行です。v1.3.0 の .env.example にあるデフォルト値は控えめです。ENGINE_WORKER_COUNT=2 は、ファイル内で小規模な 2-vCPU マシン向けの控えめなデフォルト値と説明されています。ENGINE_MAX_CONCURRENT_SCANS=1 も同様です。これらの上限として、1 つのプロバイダーアカウントで同時に実行できる root モデル呼び出し数の最大値である ENGINE_WORKERS_PER_ACCOUNT=15 があります。また、Codex セッションでは最大 5 個の子エージェントを実行できるため、ENGINE_CODEX_MAX_SUBAGENTS_PER_SESSION=5 も設定されています。大規模な VPS でワーカー数を増やすと、実行中のモデル呼び出し数も増加します。
リポジトリ内には、支出額を制限する設定はありません。.env.example に予算設定はありません。エンジン自体の停止条件は、これらのワーカー制限と ENGINE_HARNESS_TIMEOUT_SECONDS です。ENGINE_HARNESS_TIMEOUT_SECONDS は、ハーネスの 1 回の実行あたりデフォルトで 7200 秒です。そのため、上限はプロバイダー側で設定する必要があります。最初のスキャンを実行する前にプロバイダーのコンソールを開き、月間のハード上限を設定してください。スキャン後では不十分です。VPS で AI エージェントのコストを制御する では、プロバイダーごとの設定を説明しています。
ローカル側にも停止手段があります。ENGINE_WORKER_COUNT=0 を設定すると、新しいジョブの取得が一時停止します。スタックの起動後は、Settings 画面で同じワーカー値を変更できます。
リポジトリのサイズ、構築するワークフロー、その背後で使用するモデルによって費用が変わるため、このガイドではスキャン 1 回あたりの価格を示していません。まず小規模なリポジトリ 1 つに対してスキャンを 1 回実行し、大規模な対象を指定する前にプロバイダーの利用状況ページを確認してください。
スタックを起動し、正常性を確認する
./kritt start.envを確認し、少なくとも1つの認証情報があることを確認してから、docker compose up --buildを実行します。初回のビルドには時間がかかります。フロントエンド、バックエンド、エンジン、executor view、データベースのイメージをビルドするためです。また、フォアグラウンドで実行されるため、SSH セッションを閉じるとスタックが停止します。tmux内で起動するか、初回のビルドが成功した後にデタッチモードで起動してください。どちらの方法でも、再起動後に自動で復旧するわけではありません。サーバーの再起動後にもスタックを起動したい場合は、再起動後もセルフホストエージェントを実行し続けるで示した systemd unit のパターンをそのまま適用できます。
docker compose up -d --build
docker compose psdocker compose psには open-kritt-frontend、open-kritt-backend、open-kritt-engine、open-kritt-executor-view、open-kritt-dbが表示されるはずです。続いて、サーバー自身からバックエンドが応答することを確認します。
curl -s http://127.0.0.1:3002/api/healthJSON レスポンスが返れば、バックエンドは起動しています。Failed to connect to 127.0.0.1 port 3002: Connection refusedの場合は起動していません。docker compose logs backendで原因を確認できます。リポジトリのディレクトリで docker compose downを実行すると、すべてを停止できます。
任意の追加手順として、docker compose exec backend npm run seedでデモデータを読み込めます。実際のスキャンに費用をかける前に、インターフェースを確認する簡単な方法です。
SSH トンネル経由でポート 5173 の UI にアクセスする
Compose ファイル内の各サービスは、デフォルトで 127.0.0.1 にバインドされます。フロントエンドは 5173、バックエンドは 3002、executor view は 8090、Postgres は 5432 です。これらのバインドは変更せず、自分のマシンから SSH 経由でポートを転送します。
ssh -N -L 5173:127.0.0.1:5173 you@your-server-ipコマンドの実行中に、ローカルブラウザーで http://localhost:5173 を開きます。-N は、接続がポート転送を行い、シェルを開かないことを意味します。executor view も使用する場合は、同じコマンドに 2 つ目の -L 8090:127.0.0.1:8090 を追加します。
FRONTEND_BIND_ADDRESS=0.0.0.0 を設定してトンネルを省略したくなりますが、そうしないでください。バックエンドにはログイン画面がないため、そのページに到達できる人は誰でもスキャンを開始し、プロバイダーのクレジットを消費できます。さらに、もう 1 つ注意点があります。公開されたコンテナポートは ufw のデフォルトポリシーが適用される前に処理されます。そのため、ufw deny 5173 ルールは正しく見えても、何もブロックしません。ufw を迂回する Docker ポートでは、この動作を引き起こすルールチェーンを説明しています。
VPS のサイズ設定
ENGINE_MIN_FREE_STORAGE_GB のデフォルト値は 20 です。空きストレージがこの値を下回ると、エンジンはジョブごとの新しいスキャンコンテナを起動しません。ビルド済みイメージ、チェックアウトキャッシュ、Postgres のデータ、ジョブのワークスペースはすべて同じディスクに保存されます。そのため、20 GB の VPS ではスキャンがまったく開始されません。最低でも 40 GB を確保し、大規模なリポジトリをスキャンする場合はさらに増やしてください。
メモリは単純な計算で決まります。ENGINE_MEMORY_RESERVE_GB=2 は、エンジン、データベース、API、一時的なオーバーヘッドのためにメモリを確保します。また、各スキャンランナーには ENGINE_SCAN_RUNNER_MEMORY_MB=1536 の予約量とハード上限があります。そのため、2 つのワーカーを動かすには、ほかの処理を考慮する前に約 5 GB が必要です。エンジンは、残りのメモリに収まるランナーだけを起動します。小規模なサーバーではスキャンが失敗せずにキューへ入り、OOM Killer によってプロセスが強制終了されるよりも適切な動作になります。
2 つの prune 設定のデフォルト値は true です。ENGINE_AUTO_PRUNE_DOCKER_BUILD_CACHE と ENGINE_AUTO_PRUNE_UNUSED_DOCKER_IMAGES です。タスクの完了後、エンジンは未使用のビルドキャッシュ、未使用のイメージ、停止済みのスキャンコンテナを削除します。実行中のコンテナが参照しているイメージ、bind mount、データベースデータ、認証情報、ボリュームは保持されます。ホストを共有すべきでない理由が、もう 1 つあります。自分で設定していない pruner が、その Docker daemon に対して実行されるためです。
多くのユーザーが最終的に変更するエンジン設定
ENGINE_WORKER_COUNT: スキャン手順と後処理で共有するワーカースロットの総数です。新しいジョブの取得を一時停止するには 0 に設定します。ENGINE_MAX_CONCURRENT_SCANS: 同時に起動できるスキャン数です。キューに入ったスキャンは、アクティブなプールが空くまで待機します。ENGINE_MAX_WORKERS_PER_SCAN: 0 にすると、集約されたスロットをスキャン間で均等に共有します。ENGINE_HARNESS_TIMEOUT_SECONDS: デフォルトは 7200 です。1 つの処理が暴走した場合に実行できる最長時間です。ENGINE_MIN_FREE_STORAGE_GB: ストレージの下限です。ENGINE_IGNORE_LOW_STORAGE=trueにすると保護機能が無効になり、ホストのディスクが満杯になる可能性があるとファイルに警告が表示されます。ENGINE_SCAN_RUNNER_MEMORY_MB: ランナーごとのメモリ上限です。上限を削除するには 0 に設定します。
ローカルリポジトリを漏えいさせずにスキャンする
LOCAL_REPOS_PATH のデフォルト値は ./local_repos です。これはバックエンドコンテナとエンジンコンテナの /local_repos に bind mount されます。そのため、ホスト上のこのフォルダーに置いたリポジトリは、直ちにコンテナ内から見えるようになります。作業ツリーではなく、新しく clone したものを使用してください。ジョブコンテナには書き込み可能なコピーが渡され、コンテナ内では root として動作し、外部インターネットにもアクセスできます。つまり、そのコピー内にあるものは変更されたり、ホスト外へ送信されたりする可能性があります。プロジェクトをコピーする前に、.env ファイルと秘密鍵を削除してください。
取得できるものと、取得できないもの
取得できるのは、順位付けされた候補の検出結果です。検証済みの脆弱性ではありません。順位付けと重複排除によって、トリアージキュー内の順序が決まります。エントリが実在することの証明にはなりません。post-script は検証を試み、proof of concept を作成できます。これは、このツールが提供する最も強いシグナルです。ただし、post-script が失敗しても、その検出結果が誤りである証拠にはなりません。最終的には、人がすべての候補を確認します。
このガイドでは、open-kritt が検出する実際のバグの数について主張しません。測定していないためです。あなたのコードベースに対する検出率を示す人は、そのコードベースで実行していません。まず、よく把握しているリポジトリをスキャンしてください。自分で判断できる検出結果は、最も低コストで利用できるキャリブレーション材料です。
ここでは、他の多くの self-hosted ツールよりも認可が重要です。エージェントはコードをコンパイルして実行し、ネットワークにアクセスします。そのため、proof-of-concept の手順が稼働中のシステムに触れる可能性があります。自分が所有しているコード、またはテストを請け負っているコードを対象にしてください。実行前に、対象範囲を文書化してください。ANTHROPIC_API_KEY を設定して Claude Code エンジンを使用する場合は、VPS 上で Claude Code を安全に実行する に記載したサンドボックス運用の原則を、これらのエージェントにも適用してください。
FAQ
open-kritt に専用の VPS が必要なのはなぜですか?
open-kritt の分析エージェントは、書き込み可能なコードのコピーと直接のインターネットアクセスを持つ使い捨てのジョブコンテナ内で root として実行されます。また、エンジンサービスはホストの Docker ソケットをマウントし、ジョブごとに 1 個のコンテナを起動します。そのソケットに到達できるプロセスは、ホストのファイルシステムをマウントしたコンテナを起動できます。そのため、スタック全体をホスト上の root と同等に扱う必要があります。専用 VPS であれば、このトレードオフは許容できます。VPS を再構築しても失うものはありません。一方、日常的に使うワークステーションでは、スキャン対象のコードと同じ信頼境界内に SSH キーやブラウザプロファイルが置かれることになります。
SSH トンネルを使わずにポート 5173 を公開できますか?
公開すべきではありません。バックエンドにはアプリケーション認証がない状態でリリースされるため、インターネットと分析結果およびプロバイダーのクレジットの間にあるのはポートだけです。そのため、compose ファイルではすべてのサービスを 127.0.0.1 にバインドしています。代わりに ssh -N -L 5173:127.0.0.1:5173 you@your-server-ip を実行し、ローカルで http://localhost:5173 を開いてください。ufw のルールでは代替になりません。公開された Docker ポートは、ufw のデフォルトポリシーが適用される前に処理されるためです。
open-kritt が予定以上に費用を使うのを止めるにはどうすればよいですか?
最初のスキャンを実行する前に、モデルプロバイダーのコンソールでハードリミットを設定してください。open-kritt 自体には予算設定がないためです。最初の数回は、リリース時の同時実行数のデフォルト値を使い、ENGINE_WORKER_COUNT=2 と ENGINE_MAX_CONCURRENT_SCANS=1 を確認してください。また、1 つのプロバイダーアカウントではデフォルトで最大 15 個の root モデル呼び出しを同時実行でき、Codex セッションでは最大 5 個の子エージェントを実行できることにも注意してください。ENGINE_WORKER_COUNT=0 を実行すると、新しいジョブの取得が一時停止します。ローカルで最も速く停止する方法です。
どのバージョンを checkout すべきですか?
main ではなく、タグを checkout してください。git fetch --tags の後に git tag --list を実行すると利用可能なタグを確認できます。2026 年 8 月 4 日に公開された v1.3.0 が、この文書の執筆時点で最新です。バージョンを固定すると、数か月後に再構築しても同じスタックになります。また、別の日に clone した結果として更新されるのではなく、リリースノートを読んだうえで更新を判断できるようになります。
スキャンが開始されません。何を確認すべきですか?
まず空きディスク容量を確認してください。空き容量が ENGINE_MIN_FREE_STORAGE_GB 未満の場合、エンジンはジョブごとのスキャンコンテナを起動しません。デフォルト値は 20 GB です。次に、ENGINE_WORKER_COUNT が 0 でないことを確認してください。この値が 0 の場合、新しいジョブの取得が一時停止します。続いて、./kritt setup を実行してモデルの認証情報が実際に設定されていることを確認してください。GITHUB_TOKEN だけではスキャンを実行できません。ジョブをスキップした理由は docker compose logs engine に表示されます。