Локальный запуск
Поднимаем инстанс trip2g на своей машине и пушим в него волт с контентом по API. Git-remote и GIT_API_REPO_PATH не нужны: только сервер и CLI синка.
Нужно: Docker-образ trip2g (или собранный бинарь) и MinIO (S3-совместимое хранилище) для ассетов.
1. Поднять сервер
trip2g'у нужно S3-совместимое хранилище (MinIO) для ассетов. Команды ниже помещают оба контейнера в общую Docker-сеть, чтобы они обращались друг к другу по имени, и публикуют нужные порты на хост-машину. Работает на Linux, Mac и Windows.
# Общая сеть, чтобы приложение достучалось до MinIO по имени контейнера
docker network create trip2g-local-net
# MinIO (пропустить, если уже есть; подключить к той же сети)
docker run -d --name trip2g-minio \
--network trip2g-local-net \
-p 9000:9000 -p 9001:9001 \
-e MINIO_ROOT_USER=trip2g -e MINIO_ROOT_PASSWORD=trip2g-secret \
minio/minio:latest server /data --console-address ":9001"
# Приложение trip2g на порту 24081 (healthcheck на 24082), свежая локальная БД
# Скачивается актуальный опубликованный образ. Для сборки из исходников
# выполните `docker build -t trip2g:local .` в корне репозитория trip2g и замените
# тег образа ниже на `trip2g:local`.
mkdir -p /tmp/trip2g-local
docker run -d --name trip2g-local \
--network trip2g-local-net \
-p 24081:24081 -p 24082:24082 \
-e LISTEN_ADDR=0.0.0.0:24081 -e INTERNAL_LISTEN_ADDR=:24082 \
-e DB_FILE=/data/local.sqlite3 \
-e DEV=true \
-e OWNER_EMAIL=hello@example.com \
-e MINIO_ENDPOINT=trip2g-minio:9000 \
-e MINIO_ACCESS_KEY_ID=trip2g -e MINIO_SECRET_KEY=trip2g-secret \
-e MINIO_BUCKET=trip2g-local -e MINIO_USE_SSL=false \
-e PUBLIC_URL=http://localhost:24081 \
-e JWT_SECRET=dev-secret-not-for-prod \
-e USER_TOKEN_INSECURE=true \
-e GIT_API_REPO_PATH=/data/git -e GIT_API_BASE_PATH=/git \
-e RESEND_API_KEY=dev -e MAIL_FROM=dev@example.com \
-v /tmp/trip2g-local:/data \
ghcr.io/trip2g/trip2g:latest
# ждём, пока поднимется — и проверяем, что контейнер действительно запущен
docker ps | grep trip2g-local
until curl -sf http://localhost:24082/healthz >/dev/null; do sleep 1; done; echo "up"
Важно:
DEV=trueвключает dev-код входа (реальная почта не нужна). В проде не использовать.FEATURES/ векторный поиск для обычного контента не нужен: не задавайте, чтобы не тянуть embedding-сервер.-p 24081:24081 -p 24082:24082публикует порты приложения и healthcheck на хост.-p 9000:9000у MinIO делает то же самое для S3 (консоль MinIO на 9001).MINIO_ENDPOINT=trip2g-minio:9000: имя контейнера как hostname; Docker-DNS резолвит его внутри общей сети. С хоста MinIO по-прежнему доступен наlocalhost:9000.- На Linux можно обойтись без отдельной сети: добавьте
--network hostк контейнеру trip2g и укажитеMINIO_ENDPOINT=localhost:9000. Docker Desktop на Mac и Windows не поддерживает host-networking, поэтому вариант с-pявляется переносимым дефолтом.
Сборка из исходников вместо образа: make build даёт ./tmp/server; запускайте с теми же переменными (и доступным MinIO).
2. Завести API-ключ (dev-флоу)
При DEV=true сервер принимает фиксированный код входа (111111, также работает 000000). Логинимся владельцем, затем создаём ключ:
GQL=http://localhost:24081/graphql
curl -s -X POST "$GQL" -H 'Content-Type: application/json' \
-d '{"query":"mutation($i:RequestEmailSignInCodeInput!){requestEmailSignInCode(input:$i){__typename}}","variables":{"i":{"email":"hello@example.com"}}}' >/dev/null
TOKEN=$(curl -s -X POST "$GQL" -H 'Content-Type: application/json' \
-d '{"query":"mutation($i:SignInByEmailInput!){signInByEmail(input:$i){__typename ... on SignInPayload{token} ... on ErrorPayload{message}}}","variables":{"i":{"email":"hello@example.com","code":"111111"}}}' \
| grep -o '"token":"[^"]*"' | cut -d'"' -f4)
API_KEY=$(curl -s -X POST "$GQL" -H 'Content-Type: application/json' -H "Cookie: trip2g_token=$TOKEN" \
-d '{"query":"mutation($i:CreateApiKeyInput!){admin{createApiKey(input:$i){__typename ... on CreateApiKeyPayload{value} ... on ErrorPayload{message}}}}","variables":{"i":{"description":"local"}}}' \
| grep -o '"value":"[^"]*"' | cut -d'"' -f4)
echo "API-ключ: $API_KEY"
(Если задали свой USER_TOKEN_COOKIE_NAME, используйте это имя cookie вместо trip2g_token.)
3. Запушить контент
CLI синка публикует папку с нотами (.md), шаблонами _layouts/ и ассетами. Бинарь (obsidian-sync/dist/trip2g-sync.mjs) находится в репозитории trip2g; запустите из корня исходников:
node obsidian-sync/dist/trip2g-sync.mjs \
--folder /путь/к/вашему/волту \
--api-key "$API_KEY" \
--api-url http://localhost:24081/graphql \
--verbose
Непрерывная синхронизация: --watch
Флаг --watch (алиас -w) запускает CLI как долгоживущий процесс. При старте он выполняет полную двустороннюю сверку, затем удерживает два канала:
- Сервер → локально: подписывается на SSE-стрим
noteChangesи сразу записывает серверные изменения в папку волта. - Локально → сервер: следит за файловой системой и отправляет правки на сервер с дебаунсом ~500 мс.
node obsidian-sync/dist/trip2g-sync.mjs --watch \
--folder /путь/к/вашему/волту \
--api-key "$API_KEY" \
--api-url http://localhost:24081/_system/graphql
Процесс работает на переднем плане. Ctrl-C завершает его корректно. При фатальной ошибке выходит с ненулевым кодом, что удобно для перезапуска через политику контейнера или systemd.
Фильтрация: --include и --exclude
--include <glob> (-i) и --exclude <glob> (-x) управляют тем, какие пути отслеживает SSE-подписчик. Оба флага можно повторять.
# Следить только за journal/ и projects/
node obsidian-sync/dist/trip2g-sync.mjs --watch \
--folder /путь/к/волту \
--api-key "$API_KEY" \
--api-url http://localhost:24081/_system/graphql \
--include "journal/**" \
--include "projects/**"
Приоритет: флаги CLI перекрывают livePull-паттерны из data.json, которые в свою очередь перекрывают встроенный дефолт (**, следить за всем). Если никакие паттерны не заданы, отслеживаются все пути.
4. Посмотреть
Откройте permalink ноты, напр. http://localhost:24081/<путь>/<нота>.
Нота с route: yourdomain.com/ во frontmatter обслуживается на этом домене (локально нужен Host:-хедер или DNS). Для превью без DNS открывайте обычный permalink.
Используете этот инстанс как память для ИИ-агента? Смотрите ru/user/agent-memory.
Грабли
- Dev-код входа:
111111(также000000). Только приDEV=true. route:во frontmatter привязывает ноту к домену. Локально смотрите по обычному permalink (/путь/нота) или шлитеHost:-хедер.- Кастомные Jet-layout'ы: нота с
layout: <тема>/<страница>рендерится через_layouts/<тема>/<страница>.html. Если шаблон не парсится, сервер молча падает на дефолтный layout (HTTP 200). Страница «работает», но выглядит не так. - Блок-комменты
{{/* ... */}}ломают шаблонизатор в текущих сборках: не используйте их в_layouts/*.html. - Нота публична (видна анониму) только с
free: trueво frontmatter или patch-правилом**/*.md → { free: true }.