Установка и запуск
Docker Compose, всё вместе¶
Compose с обоими сервисами лежит в репозитории гейта. Начинайте оттуда: в compose панели только панель и база.
git clone https://gitlab.zebrains.team/zebrains-gate/gate zbgate
cd zbgate
cp .env.example .env
# Оба секрета — сгенерировать, не придумывать
python -c "import os,base64;print('ZBGATE_SECRET_KEY=' + base64.b64encode(os.urandom(32)).decode())"
python -c "import secrets;print('ZBGATE_SESSION_SECRET=' + secrets.token_urlsafe(48))"
docker compose up -d --build
Гейт собирается на месте, панель тянется образом из реестра. Пока CI ничего не публиковал, соберите её один раз рядом:
git clone https://gitlab.zebrains.team/zebrains-gate/admin ../zbgate-admin
docker build -t zbgate-admin:local ../zbgate-admin
ADMIN_IMAGE=zbgate-admin:local docker compose up -d --build
- Панель — http://localhost:8081, первый вход создаёт администратора
- Гейт — http://localhost:8080
ZBGATE_SECRET_KEYдолжен совпадать у обоих сервисов байт в байт. Панель им шифрует секреты провайдеров, гейт расшифровывает. Разные значения дают нечитаемые секреты и ни одного внятного сообщения об ошибке.
Схему ставит панель при старте — она ей владеет. Гейт миграции не запускает никогда.
Первые шаги после запуска¶
- Открыть панель, создать администратора (первый вход).
- Завести провайдера: имя, тип, базовый адрес — Провайдеры.
- Добавить провайдеру ключ. Кнопка «Спросить
/v1/models» проверит, что секрет рабочий, ещё до сохранения. - Перечислить модели провайдера — или оставить пусто, если провайдер один.
- Задать цены — Цены. Без них токены считаются, а стоимость остаётся нулевой.
- Создать учётную запись человека с наценкой и лимитом ключей, выдать ему ключ — Пользователи и ключи.
Гейт подхватит всё без перезапуска.
curl localhost:8080/v1/chat/completions \
-H "Authorization: Bearer <ключ из панели>" \
-H 'Content-Type: application/json' \
-d '{"model":"anthropic/claude-opus-5","messages":[{"role":"user","content":"привет"}]}'
Бой¶
ZBGATE_TAG=1.4.0 docker compose -f docker-compose.prod.yml up -d
Оба сервиса образами из реестра, теги задаются явно — не latest, чтобы
перезапуск ноды не выкатил новую версию сам по себе.
Что проверить перед первым боевым запуском:
ZBGATE_COOKIE_SECURE=true(по умолчанию так) и панель за HTTPS. На plain HTTP браузер не отдаст cookie и вход не сработает — это единственная причина выключать флаг.ZBGATE_SECRET_KEYсохранён вне репозитория и вне образа. Потеря ключа означает перевод всех ключей провайдеров заново.- Порт гейта не выставлен в интернет без нужды: авторизация в нём есть, но каталог моделей и лимиты — не замена сетевому периметру.
Порядок выката при смене схемы¶
Панель владеет схемой, гейт её читает. Миграция, которая убирает или переименовывает колонку, ломает работающий гейт старой версии. Такие миграции помечены в шапке; выкатывайте панель и гейт вместе. Подробнее — Схема и миграции.
Без Docker¶
Порядок важен: схему ставит панель, поэтому она первая.
# Postgres
docker run -d --name zbgate-pg -e POSTGRES_USER=zbgate -e POSTGRES_PASSWORD=zbgate \
-e POSTGRES_DB=zbgate -p 5432:5432 postgres:17-alpine
# Панель: зависимости, схема, сервер
cd zbgate-admin
uv venv --python 3.12 .venv && uv pip install -e '.[dev]' psycopg2-binary
# Логин и пароль базы — в PGUSER/PGPASSWORD, как для psql. Строка подключения по
# умолчанию их не содержит намеренно: пароль в исходниках — это тот пароль,
# который потом оказывается в бою.
export PGUSER=zbgate PGPASSWORD=zbgate
.venv/bin/alembic upgrade head
.venv/bin/uvicorn app.main:app --reload --port 8081
# Гейт, в другом терминале
cd ../zbgate
go build -o zbgate ./cmd/zbgate && ./zbgate -config config.yaml
Панели не нужен ни Node, ни сборка фронта: шаблоны Jinja, htmx одним файлом, CSS без препроцессора.
Проверка, что всё живо¶
curl -s localhost:8080/healthz # гейт: генерация конфига, счётчики логов
curl -s localhost:8081/healthz # панель
config_generation у гейта растёт при каждой успешной перезагрузке конфига —
если правка в панели не подействовала, смотрите на этот счётчик первым.
logs_dropped больше нуля означает, что очередь логов переполнялась.