# 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`, Ops Agents Gateway upstream — `18190`. - Старые порты `9000` и `5678` заняты старым `nodedc-demo` и не используются. ## Текущие внешние домены ```text https://id.nodedc.ru -> Authentik https://hub.nodedc.ru -> Launcher / Hub https://ops.nodedc.ru -> Tasker / Operational Core 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`. ## Локальные домены для первичной проверки На Mac для первичной проверки добавить в `/etc/hosts`: ```text 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: ```text 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 fallback `172.22.0.222` для Authentik Admin и внешние `id/hub/ops.nodedc.ru`. - `deploy-current.sh` синхронизирует compose, Caddyfile, Notification Core source, AI Workspace Hub source и опционально Launcher source в NAS mount. Authentik templates синхронизируются только при явном `SYNC_AUTHENTIK_TEMPLATES=1`. - `backup-current.sh` делает snapshot Launcher runtime/uploads/Auth templates/config и готовит команду `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: ```text http://nodedc-platform-authentik-server:9000 ``` Live `/volume1/docker/nodedc-platform/platform/.env.synology` должен содержать: ```env NODEDC_AUTHENTIK_BASE_URL=http://nodedc-platform-authentik-server:9000 AUTHENTIK_BASE_URL=http://nodedc-platform-authentik-server:9000 NODEDC_AUTHENTIK_SERVICE_TOKEN= AUTHENTIK_SERVICE_TOKEN= ``` Быстрая проверка из launcher-контейнера: ```bash 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`: ```bash cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform NAS_ROOT=/Volumes/docker/nodedc-platform \ LAUNCHER_REPO=/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher \ 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` интерактивный, поэтому команды применения печатаются в конце. Что синхронизируется: - 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`. - 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. Использовать его только осознанно: ```bash TASKER_SYNC_SOURCE=1 ./infra/synology/deploy-current.sh ``` Секретные runtime env-файлы не перетираются: - `/volume1/docker/nodedc-platform/platform/.env.synology` - `/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. ## Лёгкое обновление Hub / Launcher Для правок только в Launcher/BFF не пересоздавать Authentik, reverse-proxy, Tasker и Ops Agents: ```bash 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: ```bash 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' ``` ## 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: ```bash cd /volume1/docker/nodedc-platform/platform sudo bash clear-authentik-brand-css.sh ``` Verify: ```bash 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 '|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 '