SSD Nodes Learn 🎉 VPS від $5.50/міс
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-13

Як self-host open-kritt запустити на VPS

Налаштуйте open-kritt на VPS через Docker Compose: зафіксуйте release, відкрийте UI через SSH tunnel на port 5173 і задайте бюджет провайдера.

Чому self-host open-kritt варто запускати на VPS, а не на ноутбуці

Запускайте self-host open-kritt на сервері, який можна знищити й відновити. Інструмент запускає свої аналітичні агенти від імені root усередині одноразових job-контейнерів, надає кожному з них доступну для запису копію коду та прямий доступ до інтернету, а також монтує Docker socket хоста у свій engine service. На сервері, виділеному для цього завдання, це прийнятний компроміс. На машині, де зберігаються ваші SSH-ключі, це небезпечно.

Цю рекомендацію визначають чотири властивості стандартної конфігурації. Усі чотири випливають із власних README і compose-файлу проєкту.

Агенти мають широкі повноваження. У README зазначено, що агенти з увімкненими інструментами працюють від імені root усередині одноразових job-контейнерів, мають доступні для запису копії репозиторіїв і прямий доступ до інтернету. Тому вони можуть встановлювати інструменти, компілювати цілі, запускати тести та створювати proof of concept. Сканування — це не робота linter, який лише читає файли. Це довільне виконання коду, яке ви дозволили. Доступ до інтернету створює ризики в обох напрямках: будь-які дані, які агент отримує під час дослідження цілі, є недовіреним текстом, що потрапляє до його prompt. Це той самий ризик, який виникає, коли ви надаєте агенту власний вебпошук.

Engine має доступ до Docker socket. docker-compose.yml монтує Docker socket хоста у engine service, оскільки engine створює та запускає окремий контейнер сканування для кожного завдання. Будь-який процес, який може звернутися до цього socket, може запустити контейнер із змонтованою файловою системою хоста. Отже, engine фактично має повноваження root на хості, де він працює.

Екрана входу немає. Backend постачається без автентифікації застосунку. Доступ до порту означає доступ до результатів сканування та кредитів вашого провайдера.

Код, який ви скануєте, часто вам не належить. Якщо передати агентам сторонній репозиторій, вони збиратимуть цей репозиторій на вашій машині від імені root і з доступом до мережі.

Якщо ви прочитали чому coding agents мають працювати в одноразовій VM, то це та сама модель загроз, але з вищим рівнем ризику. Виділіть для open-kritt окремий VPS, на якому більше нічого немає, і керуйте цим VPS через окремий обліковий запис із мінімальними привілеями, а не від імені root.

Що насправді робить open-kritt

open-kritt (репозиторій — Kritt-ai/open-kritt, ліцензія AGPL-3.0) розбиває дослідження вразливостей на невеликі завдання, паралельно запускає їх на AI-агентах, а потім усуває дублікати й визначає пріоритет результатів. Workflow задається як ланцюжок цільових prompt-ів, і кожен крок отримує структурований контекст від попередніх кроків. Ціллю сканування є віддалений або локальний git-репозиторій. Для аналізу використовується Codex або Claude Code. Після появи кандидата додаткові post-script-и можуть спробувати перевірити його або створити proof of concept.

У результаті ви отримуєте впорядкований за пріоритетом список кандидатів. Розглядайте його як чергу для triage, а не як звіт.

Що потрібно підготувати

  • VPS з Ubuntu 24.04, Debian 12 або Rocky Linux 9. В інструкції зі встановлення ці дистрибутиви зазначені як перевірені для архітектур x86_64 і ARM64.
  • Docker Engine із плагіном Compose.
  • Node.js 20 або новішої версії на хості, оскільки CLI ./kritt працює на хості, а не всередині контейнера.
  • Один постачальник моделей: обліковий запис Codex або OPENAI_API_KEY, CODEX_API_KEY, ANTHROPIC_API_KEY чи OPENROUTER_API_KEY.
  • GITHUB_TOKEN потрібен лише для сканування приватних репозиторіїв. У складі .env.example це чітко зазначено: одного токена GitHub недостатньо для запуску сканування.

Спочатку встановіть 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. Докладніший опис цього налаштування наведено в розділі запуск Docker на VPS.

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 -v

node -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.0

main змінюється з часом. Тег — ні. Станом на August 2026 найновішим тегом є v1.3.0, опублікованим 4 August 2026, а git tag --list показує, що доступно на момент клонування. Перемикання на тег переводить репозиторій у стан detached HEAD. У цьому випадку це правильно: ви використовуєте цей клон як розгортання з фіксованою версією, а не як гілку для створення комітів. Щоб пізніше оновити версію, прочитайте примітки до випуску, потім виконайте git fetch --tags, перемкніться на новий тег і знову виконайте ./kritt start, оскільки start повторно збирає образи.

Не запускайте ./kritt разом із sudo. У документації це прямо зазначено. CLI керує локальними для проєкту каталогами облікових даних у .data/, тому запуск від імені root залишає власником цих каталогів root, і під час наступного звичайного запуску CLI не зможе записувати до них.

Налаштуйте доступ до моделей за допомогою ./kritt setup

./kritt setup

Команда створює .env з .env.example, якщо цього файлу ще немає, виводить стан кожного облікового даного та дає змогу встановлювати або видаляти їх. Значення ніколи не виводяться назад у термінал. І .env, і файл облікових даних рушія записуються з режимом 0600.

Якщо ви хочете виконати це вручну:

cp .env.example .env
chmod 600 .env
mkdir -p .data/codex
chmod 700 .data/codex

Потім додайте ключ провайдера у .env і залиште файл із режимом 0600. У будь-якому разі на цьому сервері тепер зберігаються чинні облікові дані провайдера. Це ще одна причина не розміщувати на сервері нічого іншого. Створіть ключ лише для цього проєкту, щоб його відкликання згодом не порушило роботу потрібних вам ресурсів. У матеріалі Не дозволяйте AI-агентам отримувати доступ до секретів описано ширший підхід.

Встановіть ліміт витрат у провайдера перед першим скануванням

open-kritt розрахований на паралельний запуск багатьох завдань, і саме за це ви платите. Типові значення у .env.example для v1.3.0 є консервативними: ENGINE_WORKER_COUNT=2, який у файлі описано як консервативне значення за замовчуванням для невеликої машини з 2 vCPU, і ENGINE_MAX_CONCURRENT_SCANS=1. Вище розташовано ENGINE_WORKERS_PER_ACCOUNT=15 — максимальну кількість одночасних викликів root-моделі в одному обліковому записі провайдера, — а також ENGINE_CODEX_MAX_SUBAGENTS_PER_SESSION=5, оскільки сеанс Codex може запускати до п’яти дочірніх агентів. Якщо збільшити кількість worker на потужнішому VPS, відповідно зросте й кількість одночасних викликів моделі.

У репозиторії немає обмеження ваших витрат. У .env.example немає параметра бюджету. Власні умови зупинки рушія — це ліміти worker і ENGINE_HARNESS_TIMEOUT_SECONDS, який за замовчуванням становить 7200 секунд на один запуск harness. Тому ліміт потрібно встановити у провайдера. Відкрийте консоль провайдера та встановіть жорсткий місячний ліміт до першого сканування, а не після нього. У матеріалі Контроль вартості AI-агента на VPS описано налаштування для кожного провайдера.

Є також локальний механізм зупинки. Значення ENGINE_WORKER_COUNT=0 призупиняє отримання нових завдань, а ті самі значення worker можна змінити на екрані Settings після запуску стека.

У цьому посібнику не наведено вартості одного сканування, оскільки вона залежить від розміру репозиторію, створеного вами workflow і моделі, яка його обробляє. Запустіть одне сканування для одного невеликого репозиторію, а потім перегляньте сторінку використання у провайдера, перш ніж запускати сканування для великого репозиторію.

Запустіть стек і перевірте його стан

./kritt start

Ця команда перевіряє .env і принаймні один обліковий ключ, а потім запускає docker compose up --build. Перше складання виконується повільно, оскільки створює образи frontend, backend, engine, executor view і database. Команда також працює у foreground, тому після закриття SSH-сеансу стек зупиниться. Запускайте його всередині tmux або після успішного першого складання запустіть у detached-режимі. Жоден із цих варіантів самостійно не переживає перезавантаження. Якщо потрібно, щоб стек запускався після перезавантаження сервера, шаблон unit для systemd з розділу як забезпечити роботу self-hosted agent після перезавантажень підходить без змін.

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. Потім перевірте, чи backend відповідає на самому сервері.

curl -s http://127.0.0.1:3002/api/health

Відповідь у форматі JSON означає, що backend працює. 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, щоб завантажити демонстраційні дані. Це простий спосіб переглянути інтерфейс, перш ніж витрачати кошти на реальне сканування.

Отримуйте доступ до UI через SSH-тунель на порту 5173

Кожен сервіс у 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 означає, що з’єднання передає трафік через тунель і не відкриває shell. Додайте другий -L 8090:127.0.0.1:8090 до тієї самої команди, якщо потрібен також executor view.

Може виникнути спокуса встановити FRONTEND_BIND_ADDRESS=0.0.0.0 і не використовувати тунель. Не робіть цього. У backend немає екрана входу, тому будь-хто, хто отримає доступ до цієї сторінки, зможе запускати сканування та витрачати кредит вашого провайдера. Є й друга проблема: опублікований порт контейнера обробляється до застосування політики за замовчуванням ufw, тому правило ufw deny 5173 може виглядати правильним, але нічого не блокувати. У статті Порти Docker, які обходять ufw показано ланцюжок правил, через який це відбувається.

Розмір VPS

ENGINE_MIN_FREE_STORAGE_GB за замовчуванням має значення 20, і engine відмовляється запускати новий scan container для окремого завдання, якщо вільного сховища менше за це значення. Зібрані images, checkout cache, дані Postgres і робочі каталоги завдань зберігаються на одному диску, тому VPS на 20 GB взагалі не запускає сканування. Вважайте 40 GB мінімальним обсягом і збільшуйте його, якщо скануєте великі репозиторії.

Обсяг пам’яті визначається простим розрахунком. ENGINE_MEMORY_RESERVE_GB=2 резервує пам’ять для engine, бази даних, API та короткочасних службових витрат, а кожен scan runner має reservation і жорстке обмеження ENGINE_SCAN_RUNNER_MEMORY_MB=1536. Тому двом workers потрібно близько 5 GB ще до запуску інших компонентів. Engine запускає лише ті runners, які вміщуються в доступний бюджет пам’яті. На невеликому сервері сканування стають у чергу, а не завершуються помилкою. Це значно кращий сценарій, ніж завершення процесів через out-of-memory killer.

Два параметри очищення за замовчуванням мають значення true: ENGINE_AUTO_PRUNE_DOCKER_BUILD_CACHE і ENGINE_AUTO_PRUNE_UNUSED_DOCKER_IMAGES. Після завершення завдання engine видаляє невикористовуваний build cache, невикористовувані images і зупинені scan containers. Images, на які посилається запущений container, bind mounts, дані бази даних, credentials і volumes зберігаються. Це ще одна причина не ділити host з іншими сервісами: не налаштований вами pruner працює з цим Docker daemon.

Параметри engine, які найчастіше змінюють
  • ENGINE_WORKER_COUNT: загальна кількість worker slots, спільна для scan steps і post-processing. Встановіть 0, щоб призупинити отримання нових завдань.
  • ENGINE_MAX_CONCURRENT_SCANS: кількість scans, які можна виконувати одночасно. Scans у черзі очікують, доки active pool не звільниться повністю.
  • ENGINE_MAX_WORKERS_PER_SCAN: значення 0 рівномірно розподіляє aggregate slots між scans.
  • ENGINE_HARNESS_TIMEOUT_SECONDS: за замовчуванням 7200. Це максимальна тривалість одного некерованого job.
  • ENGINE_MIN_FREE_STORAGE_GB: мінімальний рівень вільного сховища. ENGINE_IGNORE_LOW_STORAGE=true вимикає цей захист, і файл попереджає, що в такому разі диск host може заповнитися.
  • ENGINE_SCAN_RUNNER_MEMORY_MB: жорстке обмеження пам’яті для кожного runner. Значення 0 знімає це обмеження.

Сканування локального репозиторію без витоку даних

LOCAL_REPOS_PATH за замовчуванням має значення ./local_repos і монтується через bind mount у контейнери backend та engine за шляхом /local_repos. Тому репозиторій, який ви додаєте до цієї папки на хості, одразу стає доступним усередині контейнерів. Використовуйте свіжий clone, а не робочу копію. Job-контейнер отримує доступну для запису копію, має root усередині самого контейнера та доступ до вихідного інтернет-трафіку. Це означає, що все, що міститься в цій копії, можна змінити або передати за межі сервера. Перед копіюванням проєкту видаліть файли .env і приватні ключі.

Що ви отримуєте, а чого не отримуєте

Ви отримуєте ранжований список потенційних знахідок. Ви не отримуєте підтверджених вразливостей. Ранжування та видалення дублікатів визначають порядок у вашій черзі перевірки. Вони не доводять, що запис є справжнім. Post-scripts можуть спробувати виконати валідацію та створити proof of concept. Це найсильніший сигнал, який надає інструмент. Але невдале виконання post-script не доводить, що знахідка хибна. Людина все одно перевіряє кожну потенційну знахідку.

Цей посібник не стверджує, скільки реальних помилок знаходить open-kritt, оскільки ми цього не вимірювали. Той, хто називає показник виявлення для вашої кодової бази, не запускав інструмент на вашій кодовій базі. Спочатку проскануйте репозиторій, який ви добре знаєте. Знахідки, які ви можете оцінити самостійно, є найдешевшим доступним способом калібрування.

Авторизація тут важливіша, ніж для більшості self-hosted інструментів. Агенти компілюють і виконують код та мають доступ до мережі, тому крок зі створенням proof of concept може взаємодіяти з робочими системами. Спрямовуйте інструмент на код, яким ви володієте або який маєте право тестувати за договором, і запишіть область тестування до початку роботи. Якщо ви налаштуєте ANTHROPIC_API_KEY і використаєте рушій Claude Code, правила безпечної роботи з Claude Code у безпечний запуск Claude Code на VPS також застосовуються до цих агентів.

FAQ

Навіщо open-kritt потрібен власний VPS?

Оскільки його агенти аналізу працюють від імені root у тимчасових job-контейнерах із доступними для запису копіями вашого коду та прямим доступом до інтернету. Крім того, сервіс engine монтує сокет Docker хоста, щоб запускати окремий контейнер для кожного job. Будь-який процес, що отримує доступ до цього сокета, може запустити контейнер із змонтованою файловою системою хоста. Тому весь стек слід вважати таким, що має права root на своєму хості. На виділеному VPS це прийнятний компроміс, а повторне розгортання сервера не створює проблем. На вашій щоденній робочій станції це означає, що SSH-ключі та профілі браузера опиняються в тій самій межі довіри, що й код, який ви скануєте.

Чи можна відкрити порт 5173 замість використання SSH-тунелю?

Не слід цього робити. Backend постачається без автентифікації на рівні застосунку, тому порт є єдиним бар’єром між інтернетом і результатами аналізу та кредитами провайдера. Саме тому 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 витратив більше, ніж заплановано?

Перед першим скануванням установіть жорсткий ліміт у консолі вашого model provider, оскільки open-kritt не має власного параметра бюджету. Для перших кількох запусків залиште стандартні значення concurrency, з якими постачається продукт, ENGINE_WORKER_COUNT=2 і ENGINE_MAX_CONCURRENT_SCANS=1. Також пам’ятайте, що один обліковий запис провайдера за замовчуванням дозволяє до 15 одночасних викликів root model, а сесія Codex може запускати до п’яти дочірніх агентів. ENGINE_WORKER_COUNT=0 призупиняє отримання нових job і є найшвидшим локальним способом зупинити роботу.

Яку версію слід отримати?

Тег, а не main. Команда git fetch --tags разом із git tag --list показує доступні версії, а v1.3.0, опублікована 4 August 2026, є найновішою на момент написання. Фіксація версії гарантує, що повторне збирання через кілька місяців створить той самий стек. Вона також перетворює оновлення на свідоме рішення після ознайомлення з release notes, а не на побічний результат клонування в інший день.

Сканування не запускається. Що перевірити?

Спочатку перевірте вільне місце на диску, оскільки engine не запускатиме окремий контейнер сканування для job, якщо обсяг вільного сховища менший за ENGINE_MIN_FREE_STORAGE_GB, значення якого за замовчуванням становить 20 GB. Потім перевірте, що ENGINE_WORKER_COUNT не дорівнює 0, оскільки це значення призупиняє отримання нових job. Після цього переконайтеся, що облікові дані model provider справді налаштовані, виконавши ./kritt setup, оскільки самого GITHUB_TOKEN недостатньо для запуску сканування. docker compose logs engine вказує причину, через яку job було пропущено.