23 KiB
NODE.DC Synology deploy
Эта папка фиксирует текущий воспроизводимый NAS-deploy для nodedc-platform на Synology RS1221RP+.
Правила
- Не выполнять
docker stop,docker restart,docker compose down,docker system pruneдля старых проектов. - Новый compose project:
nodedc-platform. - Новая папка на NAS:
/volume1/docker/nodedc-platform. - Внутренний HTTP edge использует
18080, AI Workspace Hub —18081, Tasker upstream —18090, BIM Viewer upstream —18100, Ops Agents Gateway upstream —18190. - Старые порты
9000и5678заняты старымnodedc-demoи не используются.
Deploy runner
nodedc-deploy is managed outside the platform runtime tree. The synced install candidate lives in:
/volume1/docker/nodedc-deploy/runner-install/nodedc-deploy
The live root-owned runner is:
/usr/local/sbin/nodedc-deploy
deploy-current.sh syncs the runner candidate into runner-install. Promoting it to live is explicit:
sudo install -o root -g root -m 0755 \
/volume1/docker/nodedc-deploy/runner-install/nodedc-deploy \
/usr/local/sbin/nodedc-deploy
sudo /usr/local/sbin/nodedc-deploy verify-install
Текущие внешние домены
https://id.nodedc.ru -> Authentik
https://hub.nodedc.ru -> Launcher / Hub
https://ops.nodedc.ru -> Tasker / Operational Core
https://bim.nodedc.tech -> BIM Viewer
https://ops-agents.nodedc.ru -> Ops Agents Gateway / MCP
https://ai-hub.nodedc.ru -> AI Workspace Hub / WebSocket relay
id.nodedc.ru is the user-facing OIDC/login host. Authentik Admin is intentionally not exposed through this public host; /if/admin/* returns 404 there.
ai-hub.nodedc.ru is intentionally routed by Synology DSM Reverse Proxy directly to 172.22.0.222:18081, because this endpoint must carry WebSocket Upgrade traffic for remote Codex agents.
В Caddyfile.http эти домены проксируются через локальный HTTP edge, но upstream получает X-Forwarded-Proto: https и X-Forwarded-Port: 443.
bim.nodedc.tech can either be routed by DSM directly to the BIM host port 172.22.0.222:18100, or through the platform HTTP edge 172.22.0.222:18080. When it goes through the platform edge, BIM_DOMAIN=bim.nodedc.tech and SYNOLOGY_BIM_VIEWER_UPSTREAM=host.docker.internal:18100 keep the same target service.
AI Workspace Hub / Assistant contract
ai-workspace-hub remains a thin public WebSocket relay. It is the only AI Workspace service exposed through DSM/Nginx as https://ai-hub.nodedc.ru.
ai-workspace-assistant is an internal platform service for per-user executors, selected device, shared threads and installer generation. It must not be exposed as a public route. Launcher, Engine and Tasker use it through Docker networking:
NODEDC_AI_WORKSPACE_ASSISTANT_URL=http://ai-workspace-assistant:18082
PLANE_NODEDC_AI_WORKSPACE_ASSISTANT_URL=http://ai-workspace-assistant:18082
Installer generation must always point remote Codex workers to the deployed Hub:
AI_WORKSPACE_HUB_PUBLIC_URL=wss://ai-hub.nodedc.ru/api/ai-workspace/hub
AI_WORKSPACE_HUB_INTERNAL_URL=https://ai-hub.nodedc.ru
AI_WORKSPACE_HUB_FALLBACK_URLS=
Server-side Hub API calls, including executor status checks, use AI_WORKSPACE_HUB_INTERNAL_URL and require a token accepted by Hub: AI_WORKSPACE_HUB_TOKEN, NDC_AI_WORKSPACE_HUB_TOKEN, or the shared NODEDC_INTERNAL_ACCESS_TOKEN where that token is intentionally common across platform services.
Local NDC SEO Mode development uses this same server-side Hub class through SEO_AI_WORKSPACE_PROFILE=deployed-hub, SEO_AI_WORKSPACE_CONTROL_URL=https://ai-hub.nodedc.ru, and a Hub-accepted SEO_AI_WORKSPACE_CONTROL_TOKEN. The Hub only exposes an Assistant-compatible allowlist proxy for setup/probe/thread dispatch calls behind bearer-token auth; it does not expose unrestricted Assistant, product apps, Authentik, Engine, Ops, or Tasker to the remote Codex worker.
AI Workspace Assistant also calls product entitlement adapters before every Codex run. Ops uses the Agent Gateway internal endpoint; the token must match NODEDC_AGENT_GATEWAY_INTERNAL_TOKEN from the Ops Agent Gateway deployment:
AI_WORKSPACE_OPS_ENTITLEMENT_URL=http://172.22.0.222:18190/api/internal/v1/ai-workspace/entitlements
AI_WORKSPACE_OPS_ENTITLEMENT_TOKEN=<same value as Ops NODEDC_AGENT_GATEWAY_INTERNAL_TOKEN>
AI_WORKSPACE_OPS_ENTITLEMENT_REQUIRED=false
Локальные домены для первичной проверки
На Mac для первичной проверки добавить в /etc/hosts:
172.22.0.222 auth.nas.nodedc
172.22.0.222 auth-admin.nas.nodedc
172.22.0.222 launcher.nas.nodedc
172.22.0.222 task.nas.nodedc
Первичные URL:
http://auth.nas.nodedc:18080
http://auth-admin.nas.nodedc:18080/if/admin/
http://172.22.0.222:18080/if/admin/
http://launcher.nas.nodedc:18080
http://task.nas.nodedc:18080
http://task.nas.nodedc:18090
auth-admin.nas.nodedc is the technical Authentik Admin entrypoint. 172.22.0.222:18080 is a local IP fallback for workstations without auth-admin.nas.nodedc DNS. Both keep Authentik access separate from the public id.nodedc.ru login entrypoint and do not load NODE.DC auth-flow CSS.
Что входит
docker-compose.platform-http.ymlподнимает новый Authentik, Launcher, Notification Core, AI Workspace Hub и Caddy edge.Caddyfile.httpмаршрутизирует локальныеauth/auth-admin/launcher/task.nas.nodedc, IP fallback172.22.0.222для Authentik Admin и внешниеid/hub/ops.nodedc.ru.deploy-current.shсинхронизирует compose, Caddyfile, Notification Core source, AI Workspace Hub source и опционально Launcher/BIM source в NAS mount. Authentik templates синхронизируются только при явномSYNC_AUTHENTIK_TEMPLATES=1.backup-current.shделает snapshot Launcher runtime/uploads/Auth templates/config, BIM Viewerserver/dataи готовит командуpg_dumpдля Authentik Postgres.- Tasker поднимается отдельным compose из
NODEDC_TASKMANAGER/plane-app/docker-compose.yamlна порту18090. - Ops Agents Gateway поднимается отдельным compose из
NODEDC_TASKMANAGER_CODEXAPI/docker-compose.synology.ymlна172.22.0.222:18190; Synology reverse proxy должен вестиops-agents.nodedc.ruна этот порт, а не на18090.
Внутренний Authentik API для Launcher
Launcher подключен и к platform identity-сети, и к engine-сети. В engine-сети тоже может быть сервис с DNS-именем authentik-server, поэтому это имя нельзя использовать для NODEDC_AUTHENTIK_BASE_URL: Docker DNS может отдать не тот Authentik, и platform API-token будет получать 403 Token invalid/expired.
Для platform Authentik зафиксирован отдельный alias:
http://nodedc-platform-authentik-server:9000
Live /volume1/docker/nodedc-platform/platform/.env.synology должен содержать:
NODEDC_AUTHENTIK_BASE_URL=http://nodedc-platform-authentik-server:9000
AUTHENTIK_BASE_URL=http://nodedc-platform-authentik-server:9000
NODEDC_AUTHENTIK_SERVICE_TOKEN=<server Authentik API token>
AUTHENTIK_SERVICE_TOKEN=<same token>
Быстрая проверка из launcher-контейнера:
sudo /usr/local/bin/docker exec nodedc-platform-launcher-1 sh -lc '
echo "$NODEDC_AUTHENTIK_BASE_URL"
getent hosts nodedc-platform-authentik-server
for attempt in 1 2 3 4 5 6 7 8 9 10; do
wget -qSO- \
--header "Authorization: Bearer $NODEDC_AUTHENTIK_SERVICE_TOKEN" \
"$NODEDC_AUTHENTIK_BASE_URL/api/v3/core/groups/?search=nodedc_admin" \
2>&1 | head -n 25 && exit 0
echo "authentik-api-not-ready attempt=$attempt"
sleep 10
done
exit 1
'
Ожидаемый результат: HTTP/1.1 200 OK.
После изменения platform Authentik alias пересоздавать нужно authentik-server, authentik-worker и launcher. Один authentik-server может временно отдавать 503 Service Unavailable, пока worker и bootstrap не готовы.
Синхронизация текущего состояния
С Mac, при смонтированном /Volumes/docker:
cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
NAS_ROOT=/Volumes/docker/nodedc-platform \
LAUNCHER_REPO=/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher \
BIM_REPO=/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_BIM_VIEWER \
TASKER_REPO=/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER \
TASKER_CHANGED_BASE=533f8c6 \
GATEWAY_REPO=/Users/dcconstructions/Downloads/mnt/data/NODEDC_TASKMANAGER_CODEXAPI \
./infra/synology/deploy-current.sh
Скрипт не запускает Docker сам: на NAS sudo интерактивный, поэтому команды применения печатаются в конце.
По умолчанию sync source-копий на SMB/NAS не сохраняет owner/group/perms/times. Для Docker build важен контент, а macOS/Synology metadata может падать на utimensat Operation timed out. Если metadata действительно нужно сохранить для отдельного ручного случая, запускать с RSYNC_PRESERVE_METADATA=1.
Что синхронизируется:
- Platform compose/Caddy.
- Notification Core source в
/volume1/docker/nodedc-platform/platform/notification-core. - AI Workspace Hub source в
/volume1/docker/nodedc-platform/platform/ai-workspace-hub. - Authentik templates только при
SYNC_AUTHENTIK_TEMPLATES=1; по умолчанию они не трогаются, чтобы лёгкий Hub deploy не уносил экспериментальную тему/брендинг в prod. - Launcher source в
/volume1/docker/nodedc-platform/launcher/source. - BIM Viewer source в
/volume1/docker/nodedc-platform/bim-viewer/source;server/dataне синхронизируется и остаётся live runtime-хранилищем моделей, shares, comments и refs. - Tasker
plane-app/docker-compose.yamlи, если заданTASKER_CHANGED_BASE, только изменённые source-файлы из диапазонаTASKER_CHANGED_BASE..HEAD. - Ops Agents Gateway source в
/volume1/docker/nodedc-platform/ops-agents.
Полный sync Tasker source по SMB тяжёлый для Plane fork. Использовать его только осознанно:
TASKER_SYNC_SOURCE=1 ./infra/synology/deploy-current.sh
Секретные runtime env-файлы не перетираются:
/volume1/docker/nodedc-platform/platform/.env.synology/volume1/docker/nodedc-platform/bim-viewer/source/.env/volume1/docker/nodedc-platform/tasker/plane-app/.env.synology/volume1/docker/nodedc-platform/ops-agents/.env
Если emergency-fix был сделан прямо на Synology в этих env-файлах, перенести sanitized-значение в .env.synology.example/docs, а секрет оставить только в live env.
Gelios: сбор всех units доверенного подключения
GELIOS_UNIT_SCOPE=all означает все текущие и будущие units только одной уже
настроенной пары GELIOS_TENANT_ID + GELIOS_CONNECTION_ID. Это не wildcard
на другие tenants или providers. Provider credential остаётся только в Engine.
Пропавший из очередного ответа unit не удаляется: его stable provider ID и
last_seen_at сохраняются; видимость на карте — отдельная логика витрины.
Перед каноническим nodedc-deploy apply включить политику на Synology (скрипт
создаёт backup и не выводит секреты):
sudo bash /volume1/docker/nodedc-deploy/inbox/prepare-gelios-all-units-env.sh
Затем применить узкий Platform-артефакт, собранный с --gateway-only, через
nodedc-deploy. В его plan должны быть только gelios-postgres и
gelios-gateway; общий docker-compose в такой архив не входит. После apply
Gateway начинает принимать весь состав units этого подключения.
AI Hub relay-only deploy
Для локального тестирования с внешней Codex-машиной нельзя деплоить Launcher, Engine, Ops, Authentik или Tasker. Единственная допустимая удалённая точка в этой схеме — ai-workspace-hub, потому что удалённый worker должен иметь публичный WebSocket/HTTP relay.
С Mac, при смонтированном /Volumes/docker, синхронизировать только Hub source, compose и узкий apply-script:
cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
NAS_ROOT=/Volumes/docker/nodedc-platform ./infra/synology/sync-ai-hub-relay.sh
На Synology применить только ai-workspace-hub:
ssh dctouch@100.109.216.21 'cd /volume1/docker/nodedc-platform/platform && sudo bash apply-ai-hub-relay.sh'
Этот путь намеренно делает только:
- build
nodedc/ai-workspace-hub:local; docker compose up -d --no-deps --force-recreate ai-workspace-hub;- container health check;
- проверку
/api/ai-workspace/hub/v1/assistant-relays/<relayId>/poll; - public route check через
https://ai-hub.nodedc.ru.
Он не меняет .env.synology, не синхронизирует Launcher/Tasker/Ops source, не пересоздаёт Authentik, reverse-proxy, базы, storage или product containers.
После успешного relay-only deploy локальная цепочка для теста должна быть такой:
local Launcher/Engine/Ops/Auth/Assistant
-> deployed AI Hub relay: https://ai-hub.nodedc.ru
-> remote Codex worker
-> deployed AI Hub relay
-> local Assistant relay poll
-> local product services
Лёгкое обновление Hub / Launcher
Для правок только в Launcher/BFF не пересоздавать Authentik, reverse-proxy, Tasker и Ops Agents:
cd /volume1/docker/nodedc-platform/launcher/source
sudo /usr/local/bin/docker build --no-cache -t nodedc/launcher:local .
cd /volume1/docker/nodedc-platform/platform
sudo /usr/local/bin/docker compose \
--env-file /volume1/docker/nodedc-platform/platform/.env.synology \
-f /volume1/docker/nodedc-platform/platform/docker-compose.platform-http.yml \
up -d --force-recreate --no-deps ai-workspace-hub launcher
После такого deploy проверить healthz, запись в launcher storage/uploads и сценарий пользователя без аппрува: сохранение аватара не должно показывать экран Заявка ожидает подтверждения. Дополнительно проверить, что live bundle больше не содержит старый pending gate:
launcher_asset="$(
curl -k -sS --compressed -H 'Accept: text/html' https://hub.nodedc.ru/ \
| grep -aoE 'index-[A-Za-z0-9_-]+\.js' \
| head -n 1
)"
test -n "$launcher_asset"
if curl -k -sS --compressed "https://hub.nodedc.ru/assets/${launcher_asset}" \
| grep -aq 'Заявка ожидает подтверждения'; then
echo 'old pending gate still present'
exit 1
fi
echo 'launcher-pending-gate-ok'
BIM Viewer deploy
bim.nodedc.tech на Synology можно вести напрямую через DSM Reverse Proxy на 172.22.0.222:18100. В этом режиме Platform Caddy не участвует в публичном BIM-трафике, но Caddyfile.http всё равно содержит BIM route как запасной вариант для маршрута через 172.22.0.222:18080.
Canonical BIM deploy now uses nodedc-deploy with component=bim-viewer; do not deploy BIM by manually running docker compose up from the source directory as the normal path.
Live BIM root:
/volume1/docker/nodedc-platform/bim-viewer/source
Live env stays outside artifacts:
/volume1/docker/nodedc-platform/bim-viewer/source/.env
Before the first canonical apply, prepare .env from .env.synology.example and verify that NODEDC_INTERNAL_ACCESS_TOKEN matches platform/.env.synology. After that, .env must not be included in deploy artifacts.
Canonical deploy commands:
sudo /usr/local/sbin/nodedc-deploy verify-install
sudo /usr/local/sbin/nodedc-deploy plan /volume1/docker/nodedc-deploy/inbox/<bim-artifact>.tgz
sudo /usr/local/sbin/nodedc-deploy apply /volume1/docker/nodedc-deploy/inbox/<bim-artifact>.tgz
The bim-viewer runner component:
- applies payload under
/volume1/docker/nodedc-platform/bim-viewer/source; - rejects
.env,server/data, upload/model/comment/share runtime storage,node_modules,.git, shell hooks and backup files; - prepares required live runtime directories under
server/databefore compose; - builds
nodedc/bim-converter:localfromconverter/Dockerfile; - recreates only
ndc-beam-viewerandnodedc-bim-converter; - healthchecks
http://127.0.0.1:18100/api/auth/session.
Минимальная проверка после apply:
curl -k -fsS http://127.0.0.1:18100/api/auth/session
curl -k -sS -o /dev/null -w '%{http_code}\n' https://bim.nodedc.tech/
Ожидаемо: /api/auth/session возвращает authRequired: true, а прямой public root без BIM-сессии отдаёт 302 в Launcher login/launch. Public share /share/<token> должен открываться без авторизации и без toolbar.
Tasker / OPS BIM iframe rebuild
OPS web bundle получает BIM URL на build-time через VITE_BEAM_VIEWER_BASE_URL и VITE_BEAM_API_BASE_URL. После смены домена пересобрать только web image:
cd /volume1/docker/nodedc-platform/tasker/plane-src
VITE_BEAM_VIEWER_BASE_URL=https://bim.nodedc.tech \
VITE_BEAM_API_BASE_URL=https://bim.nodedc.tech \
BUILD_BACKEND=0 BUILD_WEB=1 BUILD_ADMIN=0 \
sh rebuild-nas-legacy.sh
Это пересоздаёт только web и не трогает PostgreSQL/MinIO volumes.
Authentik Admin и Brand CSS
NODE.DC auth-flow CSS must stay template-scoped. Do not store it in Authentik Brand.branding_custom_css: Authentik passes that CSS into Admin/User web component runtime and breaks native controls.
After syncing Authentik templates to NAS, recreate reverse-proxy authentik-server authentik-worker launcher, then clear existing global Brand CSS in the live DB:
cd /volume1/docker/nodedc-platform/platform
sudo bash clear-authentik-brand-css.sh
Verify:
id_admin_status="$(
curl -k -sS -o /dev/null -w '%{http_code}' https://id.nodedc.ru/if/admin/
)"
if [[ "$id_admin_status" != "404" ]]; then
echo "public id admin is not closed: status=${id_admin_status}"
exit 1
fi
echo 'public-id-admin-closed-ok'
auth_admin_page="$(
curl -k -fsS --compressed http://auth-admin.nas.nodedc:18080/if/admin/
)"
printf '%s' "$auth_admin_page" \
| grep -aE '<style data-id="brand-css"></style>|authentikBrand.branding_custom_css = ""'
auth_admin_flow="$(
curl -k -fsS --compressed http://auth-admin.nas.nodedc:18080/if/flow/default-authentication-flow/
)"
if printf '%s' "$auth_admin_flow" | grep -aq '<style data-id="nodedc-auth-login-css">'; then
echo 'admin host still has NODE.DC auth CSS'
exit 1
fi
echo 'auth-admin-css-ok'
Backup текущего состояния
С Mac, при смонтированном /Volumes/docker:
cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
NAS_ROOT=/Volumes/docker/nodedc-platform ./infra/synology/backup-current.sh
Файловый backup создаётся в /Volumes/docker/nodedc-platform/backups/platform-current-*.
Для Authentik Postgres dump нужно выполнить напечатанную команду на Synology, потому что Docker доступен через интерактивный sudo:
bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-authentik-db-dump-on-synology.sh
Для Notification Core Postgres dump:
bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-notification-db-dump-on-synology.sh
Если планируются изменения Tasker backend/schema, дополнительно выполнить:
bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-tasker-db-dump-on-synology.sh
Если Ops Agents Gateway уже был запущен и там есть production tokens/grants/audit, дополнительно выполнить:
bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-ops-agents-db-dump-on-synology.sh
Что нужно перед запуском
- Собрать или загрузить
linux/amd64images:nodedc/launcher:localnodedc/notification-core:localnodedc/plane-frontend:runodedc/plane-admin:runodedc/plane-space:runodedc/plane-live:localnodedc/plane-backend:localnodedc/plane-proxy:ru
- Для Ops Agents Gateway отдельный registry image пока не обязателен: deploy из source repo выполняется через
docker compose --env-file .env -f docker-compose.synology.yml up -d --build. - Создать
.env.synologyиз.env.synology.exampleи заменить всеreplace-with-*. - Создать
plane.env.synologyдля Tasker изplane.env.staging.example, но с HTTP URL на*.nas.nodedc:18080и портами18090/18490.
Обязательные runtime-права
Launcher пишет runtime snapshot и uploads под пользователем node (uid=1000). После создания NAS-папок:
cd /volume1/docker/nodedc-platform/platform
sudo mkdir -p ../launcher/server-storage ../launcher/uploads
sudo chown -R 1000:1000 ../launcher/server-storage ../launcher/uploads
sudo chmod -R u+rwX,g+rwX ../launcher/server-storage ../launcher/uploads
Проверка внутри контейнера:
sudo /usr/local/bin/docker exec nodedc-platform-launcher-1 sh -lc \
'touch /app/server/storage/.write-test /app/server/storage/uploads/.write-test && rm /app/server/storage/.write-test /app/server/storage/uploads/.write-test && echo storage-ok'
Проверки после деплоя
curl -k -sS --compressed https://id.nodedc.ru/if/flow/default-authentication-flow/ \
| grep -aE 'hub.nodedc.ru|launcher.local|getLauncherBaseUrl|Запросить доступ'
В выводе должны быть id.nodedc.ru -> hub.nodedc.ru и не должно быть launcher.local.