SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor

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 以降。./kritt CLI はコンテナ内ではなくホスト上で実行されるためです。
  • いずれか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 未満のバージョンでは終了します。Node 20 自体もすでにサポート終了となり、更新を受け取らないため、NodeSource から Node 22 をインストールします。Node 22 は同じ 20 以上のチェックを満たします。

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node -v

ここでは node -v が v22. を出力する必要があります。v20. 未満のバージョンは CLI によって拒否されます。Rocky Linux 9 では、同等の操作として sudo dnf module enable nodejs:22 -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.4.1

main の内容は更新されますが、タグは更新されません。2026年10月12日時点で最新のタグは v1.4.1 です。これは2026年8月16日に公開されました。git tag --list を実行すると、クローンする日に存在する内容を確認できます。v1.4.0(2026年8月12日)では、以下の sizing で説明するメモリ対応の runner admission が追加されました。v1.4.1では、ranker がユーザー指定の ranking rules を無視する不具合が修正されました。タグを checkout すると、リポジトリは detached HEAD 状態になります。ここではこれが正しい状態です。このクローンは、コミットを追加するブランチではなく、固定したデプロイメントとして扱うためです。後でアップグレードする場合は、リリースノートを確認してから git fetch --tags を実行し、新しいタグを checkout し、./kritt start をもう一度実行します。start によってイメージが再ビルドされるためです。

./kritt を sudo とともに実行しないでください。ドキュメントにも明記されています。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.4.1 の .env.example にあるデフォルト値は控えめです。ENGINE_WORKER_COUNT=2 は、ファイル内で 2-vCPU の小規模マシン向けの控えめなデフォルト値と説明されています。ENGINE_MAX_CONCURRENT_SCANS=1 も同様です。これらの上位には ENGINE_WORKERS_PER_ACCOUNT=15 があります。これは、1 つのプロバイダーアカウントで許可される root モデル呼び出しの最大同時実行数です。さらに ENGINE_CODEX_MAX_SUBAGENTS_PER_SESSION=5 もあります。1 つの Codex セッションで最大 5 個の子エージェントが実行される可能性があるためです。より大きな VPS で worker 数を増やすと、実行中のモデル呼び出し数も増加します。

リポジトリ内には、支出額を制限する設定はありません。.env.example にも予算設定はありません。エンジン自体の停止条件は、これらの worker 制限と ENGINE_HARNESS_TIMEOUT_SECONDS だけです。ENGINE_HARNESS_TIMEOUT_SECONDS のデフォルト値は、1 回の harness 実行あたり 7200 秒です。ここでいう harness は、何らかの条件で実行が終了するまで、ツールとコンテキストを使ってモデルを呼び出し続けるループです。そのため、このタイムアウトは モデルをラップするプログラム の実時間上限であり、その内部でモデルが使用できる金額の上限ではありません。したがって、上限はプロバイダー側に設定する必要があります。最初のスキャンを実行する前にプロバイダーのコンソールを開き、月間のハードリミットを設定してください。実行後では不十分です。VPS 上で AI エージェントのコストを制御する方法では、プロバイダーごとの設定を説明しています。

ローカル側にも停止手段があります。ENGINE_WORKER_COUNT=0 を設定すると、新しいジョブの取得が一時停止します。スタックの起動後は、Settings 画面で同じ worker 値を変更できます。

このガイドでは、スキャン 1 回あたりの料金を示していません。費用は、リポジトリのサイズ、構築するワークフロー、その背後で使用するモデルによって異なるためです。まず小規模なリポジトリ 1 つに対してスキャンを 1 回実行し、大規模な対象に実行する前に、プロバイダーの使用量ページを確認してください。

スタックを起動し、正常性を確認する

./kritt start

.envを確認し、少なくとも1つの認証情報があることを確認してから、docker compose up --buildを実行します。初回のビルドには時間がかかります。フロントエンド、バックエンド、エンジン、executor view、データベースのイメージをビルドするためです。また、フォアグラウンドで実行されるため、SSH セッションを閉じるとスタックが停止します。tmux内で起動するか、初回のビルドが成功した後にデタッチモードで起動してください。どちらの方法でも、再起動後に自動で復旧するわけではありません。サーバーの再起動後にもスタックを起動したい場合は、再起動後もセルフホストエージェントを実行し続けるで示した systemd unit のパターンをそのまま適用できます。

docker compose up -d --build
docker compose ps

docker 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/health

JSON レスポンスが返れば、バックエンドは起動しています。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 にバインドされます。frontend は 5173、backend は 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 も利用する場合は、同じコマンドに -L 8090:127.0.0.1:8090 を 2 つ目として追加します。

FRONTEND_BIND_ADDRESS=0.0.0.0 を設定してトンネルを省略したくなりますが、そうしてはいけません。backend にはログイン画面がないため、そのページに到達できる人は誰でもスキャンを開始でき、プロバイダーのクレジットを消費できます。対照的に、Vaultwarden はインターネットに公開する構成を想定しています。それでも、そのセキュリティ強化は管理者トークンとバックアップファイルにかかっており、open-kritt にはこのような制御手段がありません。もう 1 つ注意点があります。公開されたコンテナポートは ufw のデフォルトポリシーが適用される前に処理されるため、ufw deny 5173 ルールは正しく見えても、何もブロックしません。ufw を迂回する Docker ポートでは、その原因となるルールチェーンを示しています。

VPS のサイジング

ENGINE_MIN_FREE_STORAGE_GB のデフォルト値は 20 です。空きストレージがこの値を下回ると、エンジンはジョブごとの新しいスキャンコンテナを起動しません。ビルド済みイメージ、チェックアウトキャッシュ、Postgres のデータ、ジョブのワークスペースはすべて同じディスクに保存されます。そのため、20 GB の VPS ではスキャンが一度も開始されません。最低でも 40 GB を割り当て、大規模なリポジトリをスキャンする場合はさらに増やしてください。ストレージを大量に消費するサービスを同じホストに置いて、空いた容量を活用しようとしないでください。PhotoPrism と Immich のこの比較にある実測の RAM とディスク容量の下限からも、メディアライブラリがスキャンに必要な余裕をどれだけ速く消費するかが分かります。同じことは、スキャナーの隣では容量を使わないように見える付加機能にも当てはまります。Jellyfin のライブラリを 90 年代のレンタル店風に変更するブラウザフロントエンドでも、背後ではメディアサーバー全体とトランスコードデータがディスクを消費します。そのため、別のホストに配置してください。

メモリ使用量は単純な計算で決まります。これに関係する設定は v1.4.0 で追加されたため、上記で固定したタグには適用されますが、それより古いタグには適用されません。ENGINE_MEMORY_RESERVE_GB=2 は、エンジン、データベース、API、短時間だけ発生するオーバーヘッドのためにメモリを確保します。各スキャンランナーは、ENGINE_SCAN_RUNNER_MEMORY_RESERVATION_MB=1536 のソフト予約と ENGINE_SCAN_RUNNER_MEMORY_MB=1536 のハード上限を使用します。そのため、ワーカーが 2 つある場合、ほかの処理を始める前に約 5 GB が必要です。エンジンは、残りの予算に収まるランナーだけを実行します。小規模なホストではスキャンが失敗せずキューに入り、out-of-memory killer によって強制終了されるよりも適切に処理できます。各作業単位に専用コンテナを割り当てるツールでは、同じ計算によって必要な容量の下限が決まります。そのため、AI coworker ごとに 1 つのコンテナとブラウザを使用する OpenBot は、CPU よりも早く RAM の上限に達します。

2 つの prune 設定のデフォルト値は true です。ENGINE_AUTO_PRUNE_DOCKER_BUILD_CACHE と ENGINE_AUTO_PRUNE_UNUSED_DOCKER_IMAGES が該当します。タスクの完了後、エンジンは未使用のビルドキャッシュ、未使用のイメージ、停止したスキャンコンテナを削除します。いずれかのコンテナから参照されているイメージ、サービスコンテナ、bind mount、データベースデータ、認証情報、volume は保持されます。ホストを共有しないもう 1 つの理由でもあります。自分で設定していない pruner が、その Docker daemon に対して実行されるためです。

多くのユーザーが最終的に変更するエンジン設定
  • ENGINE_WORKER_COUNT: スキャン手順と後処理で共有するワーカースロットの合計数です。新しいジョブの取得を一時停止するには 0 に設定します。
  • ENGINE_MAX_CONCURRENT_SCANS: 同時に実行できるスキャン数です。キューに入ったスキャンは、アクティブなプールが空くまで待機します。
  • ENGINE_MAX_WORKERS_PER_SCAN: 0 にすると、合計スロットをスキャン間で均等に共有します。
  • ENGINE_HARNESS_TIMEOUT_SECONDS: デフォルトは 7200 です。1 つの暴走ジョブを実行できる最長時間です。エンジンが受け付ける範囲は 60 から 86400 までです。この範囲外の値は、0 を含めて 7200 に戻されます。
  • ENGINE_MIN_FREE_STORAGE_GB: ストレージの下限です。ENGINE_IGNORE_LOW_STORAGE=true にすると安全策が無効になり、ホストのディスクが満杯になる可能性があるとファイルに警告が表示されます。
  • ENGINE_SCAN_RUNNER_MEMORY_MB: ランナーごとのハードメモリ上限です。0 にすると上限を解除します。
  • ENGINE_SCAN_RUNNER_MEMORY_RESERVATION_MB: ランナーごとのソフト予約です。ジョブの実行可否を判定する際に使用されます。これを下げるとアイドル状態のメモリを超過割り当てできますが、ハード上限によって急激な使用量の増加は抑えられます。

ローカルリポジトリを漏えいさせずにスキャンする

LOCAL_REPOS_PATH はデフォルトで ./local_repos に設定され、backend コンテナと engine コンテナに読み取り専用で bind mount されます。そのため、ホスト上のこのフォルダーに置いたリポジトリは、すぐにコンテナ内から見えるようになります。作業ツリーではなく、新しい clone を使用してください。job コンテナには書き込み可能なコピーが渡され、コンテナ内では root として動作し、外部インターネットへアクセスできます。つまり、そのコピー内にあるものは変更されたり、ホスト外へ送信されたりする可能性があります。プロジェクトをコピーする前に、.env ファイルと秘密鍵を削除してください。

返されるものと、返されないもの

返されるのは、候補となる検出結果を順位付けしたものです。検証済みの脆弱性が返されるわけではありません。順位付けと重複排除によって、トリアージキューの順序が決まります。エントリが実在することの証明にはなりません。後処理スクリプトで検証を試み、概念実証を作成できます。これは、このツールが提供する最も強いシグナルです。ただし、後処理スクリプトが失敗しても、その検出結果が誤りである証拠にはなりません。候補は、最終的に人がすべて確認します。候補と証明の間には、このような差があります。そのため、自分で再実行できる証拠をエージェントに求めるという考え方をここでも取り入れる価値があります。必要なときに再現できる検出結果は、信頼するしかない順位付きの検出結果より価値があります。

このガイドでは、open-kritt が実際のバグをいくつ検出するかについて主張しません。測定していないためです。あなたのコードベースに対する検出率を示す人がいても、そのコードベースで実行したとは限りません。まず、十分に把握しているリポジトリをスキャンしてください。自分で判定できる検出結果は、最も低コストで利用できる調整材料です。

ここでは、他の多くのセルフホスト型ツールより認可が重要です。エージェントはコードをコンパイルして実行し、ネットワークにも接続します。そのため、概念実証の手順で稼働中のシステムにアクセスする可能性があります。自分が所有しているコード、またはテストを委託されているコードを対象にしてください。実行前に、対象範囲を文書化してください。ANTHROPIC_API_KEY を設定して Claude Code エンジンを使用する場合は、VPS 上で Claude Code を安全に実行するで説明しているサンドボックス運用の習慣を、これらのエージェントにも適用してください。

FAQ

open-kritt に専用の VPS が必要なのはなぜですか?

open-kritt の分析エージェントは、書き込み可能なコードのコピーと直接のインターネットアクセスを持つ使い捨てのジョブコンテナ内で root として実行されます。また、エンジンサービスはホストの Docker socket をマウントし、ジョブごとに 1 つのコンテナを起動します。その socket に到達できるプロセスは、ホストのファイルシステムをマウントしたコンテナを起動できます。そのため、スタック全体をホスト上の root と同等に扱う必要があります。専用 VPS であれば、このトレードオフは許容できます。サーバーを再構築しても失うものはありません。一方、普段使うワークステーションでは、スキャン対象のコードと同じ信頼境界内に SSH 鍵やブラウザプロファイルが置かれることになります。

SSH トンネルを使わずに port 5173 を公開できますか?

公開すべきではありません。バックエンドにはアプリケーション認証が設定されていないため、インターネットとスキャン結果およびプロバイダーのクレジットの間にあるのはポートだけです。そのため、compose ファイルはすべてのサービスを 127.0.0.1 に bind します。代わりに 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 月 16 日に公開された v1.4.1 が、2026 年 10 月 12 日時点で最新です。バージョンを固定すると、数か月後に再構築しても同じスタックになります。また、異なる日に clone した結果として更新されるのではなく、リリースノートを読んだうえで更新を判断できるようになります。

スキャンが開始されません。何を確認すべきですか?

まず空きディスク容量を確認してください。空き容量が ENGINE_MIN_FREE_STORAGE_GB 未満の場合、エンジンはジョブごとのスキャンコンテナを起動しません。この値のデフォルトは 20 GB です。次に、ENGINE_WORKER_COUNT が 0 ではないことを確認してください。この値が 0 の場合、新しいジョブの取得が一時停止します。その後、./kritt setup を実行して、モデルの認証情報が実際に設定されていることを確認してください。GITHUB_TOKEN だけではスキャンを実行できません。ジョブをスキップした理由は docker compose logs engine に表示されます。