Predictor X

Быстрый старт on-premice

Запустите Предиктор Икс на собственном сервере или локальной машине с помощью Docker (или Helm в Kubernetes). Занимает около 10 минут.

На этой странице описан процесс запуска сервера Предиктор Икс (бэкенд + фронтенд + PostgreSQL) на вашей собственной машине или сервере с помощью Docker. После завершения настройки ваши данные будут полностью под вашим контролем — включая рабочие пространства, задачи, комментарии и конфигурацию агентов.

Выполнение задач агентами по-прежнему опирается на демон, запущенный локально, и на AI-инструменты разработки, установленные на этой машине — точно так же, как и в облачной версии (Cloud). On-premice заменяет серверный слой, а не слой выполнения.

Системные требования

  • Установленный Docker с поддержкой docker compose
  • Git (необязательно, но рекомендуется для клонирования исходного кода)
  • Машина, которая может оставаться включенной (подойдет локальный ПК, внутренняя сеть или облачный хостинг)
  • Как минимум один AI-инструмент разработки, установленный на машине, где запущен демон (не обязательно на той, где работает сервер — ваш рабочий ноутбук отлично подойдет)

1. Клонирование проекта и запуск бэкенда

Уже используете Kubernetes? Пропустите шаг с Docker и используйте Helm-чарт — перейдите к разделу Развертывание в Kubernetes ниже, а затем вернитесь к Шагу 4 для первого входа.

Команда make selfhost выполнит следующие действия:

  1. Создаст файл .env на основе .env.example, если он отсутствует, со случайными значениями JWT_SECRET и пароля Postgres.
  2. Скачает официальные Docker-образы (PostgreSQL, бэкенд Предиктор Икс, фронтенд Предиктор Икс).
  3. Запустит все службы с помощью docker-compose.selfhost.yml.
  4. Дождется готовности эндпоинта /health бэкенда.

Для периодических проверок работоспособности (probes) в продакшене после запуска используйте эндпоинт /readyz, если хотите, чтобы проверка возвращала ошибку при проблемах с базой данных или миграциями.

Контейнер бэкенда автоматически запускает миграции базы данных при старте (docker/entrypoint.sh выполняет ./migrate up перед запуском сервера) — вы увидите вывод миграций в логах бэкенда. Обновление версий происходит аналогичным образом.

Образ еще не опубликован? Если make selfhost не может скачать образы, возможно, вы находитесь на невыпущенном теге версии. Переключитесь на стабильный релиз или соберите проект из исходного кода: make selfhost-build.

После запуска:

Порты прослушиваются только на 127.0.0.1. Файл docker-compose.selfhost.yml привязывает все опубликованные порты к локальной петле (loopback) — команда ss -tlnp не покажет 0.0.0.0:8080, и службы по умолчанию недоступны с других машин. Секреты и учетные данные Postgres никогда не должны находиться в открытом доступе в интернете. Для доступа с других машин настройте обратный прокси-сервер (reverse proxy) с TLS-терминацией перед вашим стеком — см. Шаг 5b — Доступ с других машин: настройка обратного прокси.

2. Важно: держите включенной защиту продакшена

По умолчанию docker-compose.selfhost.yml устанавливает APP_ENV в значение production и оставляет переменную PREDICTORX_DEV_VERIFICATION_CODE пустой, чтобы на публичных инстансах не было фиксированного проверочного кода.

Задавайте PREDICTORX_DEV_VERIFICATION_CODE только для локального или приватного автоматического тестирования. Если фиксированный код включен, а переменная APP_ENV имеет значение, отличное от production, любой, кто может запросить код, сможет войти в систему с этим фиксированным значением. См. Настройка авторизации → Фиксированные коды для локального тестирования.

Перед любым публичным развертыванием убедитесь, что в .env указано APP_ENV=production, а переменная PREDICTORX_DEV_VERIFICATION_CODE пуста.

3. Настройка почтовой службы (необязательно, но рекомендуется)

Без настроенной почты пользователи не смогут получать коды верификации по email; в этом случае сервер будет выводить сгенерированные коды в стандартный поток вывода (stdout).

Поддерживаются два варианта отправки писем — выберите подходящий для вашей сети:

Вариант А — Resend (для облачных / публичных развертываний):

  1. Зарегистрируйтесь на Resend и получите API-ключ.

  2. Подтвердите домен-отправитель, которым вы управляете.

  3. Укажите следующие параметры в .env:

    RESEND_API_KEY=re_xxxxxxxxxxxx
    RESEND_FROM_EMAIL=noreply@yourdomain.com

Вариант Б — SMTP-релей (для внутренних сетей / on-premise):

Используйте этот вариант, если развертывание не имеет доступа к api.resend.com или у вас уже есть внутренний почтовый релей (Microsoft Exchange, Postfix, локальный SendGrid и т. д.). Если заданы оба варианта, SMTP_HOST имеет приоритет перед Resend, поэтому письма авторизации и приглашений будут отправляться через внутренний релей. Опция STARTTLS обновляется автоматически, если она поддерживается сервером; порт 465 (SMTPS / неявный TLS) автоматически активирует TLS-рукопожатие при подключении, а директива SMTP_TLS=implicit (синонимы: smtps, ssl) принудительно включает его на нестандартных портах SMTPS.

Для анонимного внутреннего релея Exchange (порт 25) (когда хост является доверенным по IP-адресу и отправляет почту без авторизации):

SMTP_HOST=exchange.internal.example.com
SMTP_PORT=25
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_TLS_INSECURE=false
RESEND_FROM_EMAIL=noreply@yourdomain.com  # повторно используется в заголовке From:

Для авторизованной отправки (порт 587, STARTTLS) (когда релей требует учетную запись службы; STARTTLS обновляется автоматически при наличии поддержки):

SMTP_HOST=smtp.internal.example.com
SMTP_PORT=587
SMTP_USERNAME=predictorx
SMTP_PASSWORD=...
SMTP_TLS_INSECURE=false        # установите в true только для приватных CA / самоподписанных сертификатов
RESEND_FROM_EMAIL=noreply@yourdomain.com

Для неявного TLS / SMTPS (порт 465) (для провайдеров вроде корпоративной почты Aliyun / Tencent, которые не анонсируют STARTTLS). Порт 465 автоматически включает неявный TLS, поэтому указывать SMTP_TLS здесь необязательно:

SMTP_HOST=smtp.qiye.aliyun.com
SMTP_PORT=465
SMTP_USERNAME=predictorx@yourdomain.com
SMTP_PASSWORD=...
SMTP_TLS=implicit              # необязательно на порту 465; обязательно на нестандартном порту SMTPS
RESEND_FROM_EMAIL=noreply@yourdomain.com

Для строгих публичных релеев (например, Google Workspace smtp-relay.gmail.com), которые отклоняют приветствие localhost по умолчанию при отправке с публичного IP: установите SMTP_EHLO_NAME в значение FQDN, которое ожидает релей — иначе соединение будет разорвано и вернет ошибку EOF на последующих командах. По умолчанию используется имя хоста контейнера, которое обычно не является валидным FQDN:

SMTP_HOST=smtp-relay.gmail.com
SMTP_PORT=587
SMTP_EHLO_NAME=mail.yourdomain.com   # FQDN, который принимает релей; по умолчанию используется имя хоста контейнера (не FQDN)
RESEND_FROM_EMAIL=noreply@yourdomain.com

Затем перезапустите службу: docker compose -f docker-compose.selfhost.yml restart backend. При перезапуске бэкенд выведет в лог информацию о том, какой провайдер был выбран и какой режим TLS согласован (EmailService: SMTP relay <host>:<port> (starttls|implicit-tls) from=… / Resend API / DEV mode) — учетные данные никогда не логируются, поэтому эту строку можно безопасно отправлять при обращении в поддержку.

Дополнительные сведения о настройке авторизации (OAuth, список разрешенных адресов для регистрации) и полный справочник переменных SMTP см. в разделах Настройка авторизации и Переменные окружения → Почта.

4. Первый вход и создание рабочего пространства

Откройте http://localhost:3000:

  • Введите свой email.
  • Получите проверочный код из настроенного почтового ящика (через Resend или SMTP-релей). Если отправка почты не настроена, скопируйте код из логов контейнера бэкенда — ищите строку [DEV] Verification code.
  • Не используйте код 000999, если вы явно не задали переменную PREDICTORX_DEV_VERIFICATION_CODE=888888 на приватном инстансе, отличном от продакшена.
  • Войдите в систему и создайте первое рабочее пространство.

5. Настройка CLI для работы с вашим сервером

Установка CLI выполняется так же, как и в Быстром старте Cloud → 2. Установка CLI — выберите Homebrew, скрипт или PowerShell.

5a. На той же машине

Если CLI и сервер запущены на одном хосте, настройки по умолчанию уже подходят:

predictorx setup self-host

Эта команда перенаправит CLI на http://localhost:8080 (бэкенд) и http://localhost:3000 (фронтенд), проведет вас через авторизацию в браузере, сохранит персональный токен доступа (PAT) локально и автоматически запустит демон.

5b. Доступ с других машин: настройка обратного прокси

Поскольку стек compose прослушивает только интерфейс 127.0.0.1, демон на другой машине не сможет напрямую подключиться к http://<server-ip>:8080 — к тому же, открывать секреты сервера в публичный интернет крайне небезопасно. Разверните на сервере обратный прокси-сервер, который будет терминировать TLS и перенаправлять трафик на 127.0.0.1:8080 (бэкенд) и 127.0.0.1:3000 (фронтенд), после чего укажите CLI ваш публичный HTTPS-адрес:

predictorx setup self-host \
  --server-url https://<your-domain> \
  --app-url https://<your-domain>

Предпочитаете переменные окружения вместо флагов? Команда setup self-host считывает переменные PREDICTORX_SERVER_URL и PREDICTORX_APP_URL, если соответствующие флаги опущены (флаг имеет приоритет перед переменной). PREDICTORX_SERVER_URL также принимает формат демона ws://…/ws из Переменных окружения и автоматически приводит его к базовому HTTP-адресу.

Пример минимального файла Caddyfile для проксирования фронтенда и бэкенда (с поддержкой WebSockets, необходимой для работы демона и веб-приложения) на одном доменном имени:

predictorx.example.com {
    # Маршрут WebSocket — должен быть указан перед общим обработчиком
    @ws path /ws /ws/*
    handle @ws {
        reverse_proxy 127.0.0.1:8080 {
            flush_interval -1
        }
    }

    # API бэкенда
    handle /api/* {
        reverse_proxy 127.0.0.1:8080
    }

    # Все остальные запросы → фронтенд
    reverse_proxy 127.0.0.1:3000
}

После запуска прокси-сервера установите переменную FRONTEND_ORIGIN=https://predictorx.example.com в файле .env вашего сервера и перезапустите бэкенд — иначе проверка источника WebSocket отклонит подключение из браузера (Устранение неполадок → WebSocket не может подключиться).

Cloudflare Tunnel — еще один отличный вариант, обеспечивающий TLS и публичное доменное имя без необходимости открывать какие-либо порты на хосте. Эквивалентная конфигурация Nginx (с разделением на поддомены app. / api. и заголовком proxy_set_header Upgrade для WebSockets) также отлично подойдет. Ключевые требования: TLS-терминация и пересылка заголовка Upgrade для путей /ws.

6. Создание агента и назначение первой задачи

Процесс аналогичен облачной версии — см. раздел Быстрый старт Cloud → Шаги 5-6.

7. Агрегация использования данных (не требует действий оператора)

Панели мониторинга использования и времени выполнения (Usage / Runtime) считывают данные из производной таблицы task_usage_hourly, заполняемой функцией rollup_task_usage_hourly(). Начиная с версии MUL-2957, бэкенд запускает эту агрегацию внутри процесса через встроенный планировщик базы данных. Использование расширения pg_cron или внешних cron-задач / системных таймеров systemd больше не требуется. Стандартный образ pgvector/pgvector:pg17 работает без каких-либо изменений.

Встроенный планировщик срабатывает каждые 30 секунд и резервирует 5-минутный интервал выполнения по UTC через таблицу sys_cron_executions. Это безопасно при использовании нескольких реплик бэкенда: уникальный ключ (job_name, scope_kind, scope_id, plan_time) гарантирует, что только одна реплика выиграет планирование конкретного интервала. Дополнительная настройка для новых инсталляций не требуется.

Совместимость с существующими регистрациями в pg_cron. Если ранее вы регистрировали задачу агрегации через pg_cron (SELECT cron.schedule('rollup_task_usage_hourly', '*/5 * * * *', …)), удалять ее необязательно: SQL-функция внутри удерживает рекомендательную блокировку (advisory lock) с кодом 4246, предотвращая одновременную запись от планировщика приложения и pg_cron. Чтобы удалить ставшую ненужной запись:

SELECT cron.unschedule('rollup_task_usage_hourly')
  FROM cron.job WHERE jobname = 'rollup_task_usage_hourly';

Обновление с версии v0.3.4 на v0.3.5+. В предыдущем релизе операторам требовалось вручную запустить cmd/backfill_task_usage_hourly перед применением миграции 103, иначе защитный механизм прерывал выполнение ./migrate up. Начиная с MUL-2957, этот процесс полностью автоматизирован: команда миграции запускает идемпотентное фоновое заполнение за месяц (под рекомендательной блокировкой 4246) непосредственно перед выполнением миграции 103, а затем продолжает работу. Вы по-прежнему можете запустить автономное заполнение на сильно нагруженной БД, чтобы снизить нагрузку на чтение с помощью параметра --sleep-between-slices=2s, но теперь это необязательно.

Полный справочник, включая операционные заметки и структуру развертывания в Kubernetes, находится в репозитории проекта: SELF_HOSTING_ADVANCED.md → Usage Dashboard Rollup.

Развертывание в Kubernetes (альтернатива)

Если вы уже используете Kubernetes, в репозитории поставляется Helm-чарт, расположенный в папке deploy/helm/predictorx/. Это аналог запуска make selfhost для K8s — те же образы бэкенда, фронтенда и базы данных Postgres pgvector/pgvector:pg17, упакованные в ресурсы Deployments, Services и Ingresses с единым ConfigMap, генерируемым на основе файла values.yaml. Разработано и протестировано на связке k3s + Traefik + local-path и должно успешно работать на любом кластере с настроенным Ingress-контроллером и дефолтным StorageClass с поддержкой режима ReadWriteOnce.

Чарт не шаблонизирует секретные значения. Он ссылается на существующий Secret с именем predictorx-secrets, поэтому реальные ключи JWT, БД, Resend или Google никогда не попадут в Git или файл values.yaml. Создайте пространство имен и Secret один раз с помощью kubectl:

kubectl create namespace predictorx

kubectl -n predictorx create secret generic predictorx-secrets \
  --from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
  --from-literal=POSTGRES_PASSWORD="$(openssl rand -hex 16)" \
  --from-literal=RESEND_API_KEY="" \
  --from-literal=GOOGLE_CLIENT_SECRET="" \
  --from-literal=CLOUDFRONT_PRIVATE_KEY="" \
  --from-literal=Предиктор Икс_DEV_VERIFICATION_CODE=""

Затем установите чарт:

cd predictorx
helm install predictorx deploy/helm/predictorx -n predictorx

Настройки по умолчанию предполагают использование хостов predictorx.dev.lan (веб-приложение) и api.predictorx.dev.lan (бэкенд). Добавьте их в ваш /etc/hosts (или на локальный DNS-сервер), указав IP-адрес любой ноды, на которой доступен ваш Ingress. Для изменения доменных имен скопируйте файл deploy/helm/predictorx/values.yaml, отредактируйте параметры ingress.frontend.host / ingress.backend.host и соответствующие значения backend.config.appUrl / frontendOrigin / localUploadBaseUrl / googleRedirectUri, после чего выполните установку с флагом -f my-values.yaml.

При первом «холодном» старте кластера бэкенд может оставаться в статусе Running, но не переходить в Ready в течение нескольких минут, пока он ожидает готовности Postgres и выполняет миграции — это предусмотрено в startupProbe, поэтому под не должен перезапускаться. Когда статус сменится на Ready:

curl -H "Host: api.predictorx.dev.lan" http://<ingress-ip>/healthz
# {"status":"ok","checks":{"db":"ok","migrations":"ok"}}

Затем откройте http://predictorx.dev.lan и продолжите выполнение инструкций с Шага 4 — Первый вход. Настройте CLI на использование ваших хостов Ingress:

predictorx setup self-host \
  --server-url http://api.predictorx.dev.lan \
  --app-url http://predictorx.dev.lan

Чтобы обновить образы до актуальных версий без изменения чарта, выполните: kubectl -n predictorx rollout restart deploy/predictorx-backend deploy/predictorx-frontend. Для фиксации конкретного релиза Предиктор Икс укажите теги images.backend.tag / images.frontend.tag в вашем файле значений и выполните helm upgrade. Команда helm -n predictorx uninstall predictorx удалит рабочие нагрузки, но сохранит PVC и Secret. Для полной очистки ресурсов удалите пространство имен: kubectl delete namespace predictorx.

Полный справочник, содержащий описание трех режимов авторизации, обходной путь ExternalName для запеченного на этапе сборки адреса REMOTE_API_URL в образе фронтенда, лимиты ресурсов и настройку TLS, находится в репозитории: SELF_HOSTING.md.

Распространенные проблемы

  • Бэкенд не запускается: проверьте логи контейнера командой docker compose -f docker-compose.selfhost.yml logs backend. Обычно проблема кроется в неверно указанных DATABASE_URL или JWT_SECRET в файле .env.
  • Не приходит проверочный код: не настроен почтовый шлюз (ни Resend, ни SMTP) → ищите строку [DEV] Verification code в выводе docker compose logs backend.
  • WebSocket не подключается: для публичных инсталляций необходимо обязательно установить переменную FRONTEND_ORIGIN в значение вашего реального домена фронтенда; подробности в разделе Устранение неполадок → WebSocket не может подключиться.
  • Данные на панелях Usage / Runtime остаются нулевыми: не запускается планирование функции rollup_task_usage_hourly() — см. Шаг 7 выше и раздел Устранение неполадок → Панель использования показывает нули.
  • Команда migrate up завершается с ошибкой refusing to drop legacy daily rollups: это защитный механизм при обновлении с версии v0.3.4 на v0.3.5+. Начиная с MUL-2957, запуск автозаполнения происходит автоматически перед применением миграции 103 — см. Шаг 7.

Что дальше?