Skip to content

🔗 Подключение к платформе ​

📌 Описание ​

Демон полностью автономен: всё работает через CLI и локальный API, без учётной записи в платформе. Подключение к AdminService.Cloud необязательно и добавляет сверху панель управления, AI-ассистента, команды и роли.

Связь устанавливается одноразовым токеном регистрации, который выдаётся в панели. Токен можно передать сразу установщику либо позже — командой asc connect.

🎯 Сценарии ​

  • Оператор копирует команду установки из панели и выполняет её на чистом сервере: демон ставится и регистрирует ноду за один шаг.
  • Платформа сама заходит по SSH, ставит демон и передаёт тот же токен.
  • Ноду, установленную раньше без платформы, подключают позже: sudo asc connect <токен>.
  • Регистрация не прошла, потому что платформа была недоступна: демон всё равно работает локально, а оператор повторяет попытку через asc connect.

🏗️ Техническое решение ​

Команда установки ​

bash
curl -fsSL https://raw.githubusercontent.com/AdminServiceCloud/asc-daemon/main/install.sh \
  | sudo bash -s -- --silent --token <ТОКЕН> --url https://adminservice.cloud
ОпцияЗначение
--silentПринять настройки по умолчанию и ничего не спрашивать — режим, который использует платформа. Docker при этом ставится: нода, которая не умеет запускать контейнерные приложения, — не рабочая нода
--no-dockerНе устанавливать Docker даже с --silent
--directОткрыть API в сеть по TLS, чтобы платформа обращалась к нему без SSH-туннеля
--token <ТОКЕН>Одноразовый токен регистрации; привязывает ноду к выдавшей его организации
--url <URL>Базовый URL платформы, по умолчанию https://adminservice.cloud

Принимаются обе формы: --token <значение> и --token=<значение>. Токен проверяется до использования и может содержать только буквы, цифры, - и _. Отдельный --url отклоняется: без токена регистрировать нечего.

install.sh пробрасывает опции в asc-updater install, который сначала устанавливает демон, а регистрирует уже после.

asc connect ​

bash
sudo asc connect <ТОКЕН> [--url https://adminservice.cloud]

Требует root: команда пишет файлы, принадлежащие root. Она сохраняет токен, запоминает URL платформы и вызывает endpoint регистрации — тот же путь, что и у установщика, но без переустановки. asc status показывает платформу и id ноды либо сообщает, что нода не подключена.

Где что хранится ​

ЧтоГдеДоступ
Токен регистрации/etc/asc/platform.token0600, только root
URL платформы, id ноды, время регистрациисекция [platform] в /etc/asc/config.toml0644

Разделение следует правилу, которое уже записано в самом конфиге: секреты никогда не лежат в config.toml — он намеренно доступен на чтение всем, чтобы любой пользователь мог посмотреть настройки демона.

toml
[platform]
url = "https://adminservice.cloud"
node_id = "0e2f…"
registered_at = "2026-08-20T09:31:04Z"

Запрос регистрации ​

Демон отправляет один запрос на публичный bootstrap-endpoint платформы:

POST <url>/bootstrap/asc.node.v1.BootstrapService/RegisterNode
Content-Type: application/json

{"token":"…","hostname":"…","primaryIp":"…","os":"…","arch":"x86_64","daemonVersion":"0.10.0"}

Тело уходит через stdin, а не аргументом командной строки, поэтому токен не виден в выводе ps. Платформа гасит токен — он работает ровно один раз — и отвечает идентификаторами ноды и организации.

URL с http:// разрешён для локальной разработки, но выводится предупреждение: токен пойдёт по сети незашифрованным.

Обработка ошибок ​

Регистрация никогда не роняет установку. Если платформа недоступна, установщик печатает предупреждение и завершается успешно: демон установлен и работает локально, а asc connect повторит попытку в удобный момент.

Живость ноды ​

Платформа спрашивает статус демона вызовом asc.daemon.v1.DaemonService/GetStatus. Нода, чей демон ответил, показывается как online; не ответил — offline. Дойти до демона вызов может двумя путями.

Через SSH (по умолчанию). API остаётся на loopback, платформа пробрасывает запрос по уже открытому SSH-подключению. Наружу ничего не выставляется; токен /etc/asc/api.token платформа читает при установке.

Напрямую (--direct). API переезжает на 0.0.0.0 и поднимает TLS. Эти два изменения включаются только вместе: bearer-токен даёт полный контроль над машиной, поэтому открывать порт без шифрования нельзя. Сертификат самоподписанный — у нод нет собственного домена — и платформа закрепляет его SHA-256-отпечаток при регистрации, ровно как закрепляет SSH host key. Токен API демон передаёт платформе внутри вызова регистрации: без SSH другого способа доставить его нет.

Нода, установленная обычной командой без --direct, сообщить свой статус не может вовсе: у платформы нет ни SSH-доступа, ни endpoint'а для запроса.

toml
[api]
listen = "0.0.0.0:8420"
tls = "self_signed"   # off | self_signed | acme | files
# Имя, по которому платформа обращается вместо адреса, — нода переживёт смену
# IP. В режиме self_signed оно вшивается в сертификат как SAN.
# domain = "node.example.com"
# tls = "files" — использовать сертификат оператора:
# tls_cert = "/etc/asc/fullchain.pem"
# tls_key  = "/etc/asc/privkey.pem"

Сертификат и ключ лежат рядом с config.toml: api.crt (0644) и api.key (0600). Команды asc api tls и asc api listen записывают эти настройки и проверяют их до записи, поэтому неработоспособная конфигурация отклоняется там, где её вводят, а не при следующем запуске.

🔐 Чем подтверждается сертификат (DMN-067) ​

tlsЧто ручается за сертификат
self_signedНичто, поэтому платформа закрепляет его SHA-256-отпечаток при регистрации — тот же контракт, что и у SSH host key.
acmeПубличный CA — когда демон научится получать сертификат сам. Пока недоступно: в этом режиме демон не запускается; тот же результат даёт files с сертификатом от certbot.
filesТот, кто выпустил установленный вами сертификат. Платформа проверяет цепочку и имя хоста; если демон при этом сообщает отпечаток — сертификат от приватного CA, — платформа закрепляет его.

Отпечаток сообщается для self_signed и files. У files сертификат может быть от приватного CA (например, Cloudflare Origin), и тогда за него может поручиться только отпечаток; acme проверяется по цепочке — закрепление сломало бы ноду при первом же продлении.

🪪 Сертификат от платформы (DMN-127) ​

TokenService.SetApiCertificate(certificate_pem, private_key_pem, domain) — только основным токеном. Демон проверяет пару (сертификат разбирается, ключ совпадает), пишет её рядом с config.toml — api-custom.crt (0644) и api-custom.key (0600) — и переводит [api] на tls = "files" с этими путями (и доменом, если передан). Если слушатель уже работает по TLS, сертификат подменяется на лету: новые подключения получают его сразу, уже открытые (включая сам вызов) — нет. Ответ — отпечаток нового сертификата и restart_required, если слушатель сейчас без TLS. Capability — api.certificate.

📡 Сообщение об изменении после регистрации (DMN-068) ​

Регистрация — одноразовое погашение токена, поэтому сообщить о том, что адрес или сертификат изменились позже, она не может. Для этого демон вызывает BootstrapService.ReportNodeEndpoint — при старте, если вычисленный endpoint отличается от сообщённого в прошлый раз, и после asc api tls. Вызов аутентифицируется основным API-токеном ноды, единственным общим секретом сторон, и может изменить только то, как до ноды дозваниваться: ни организацию, ни удалённую ноду он не трогает.

Что было сообщено в прошлый раз, кэшируется в config.toml ([platform] reported_endpoint / reported_fingerprint), чтобы демон, перезапустившийся без изменений, не дёргал платформу при каждой загрузке.

Что пока не реализовано ​

Постоянного канала с платформой нет. Зарегистрированная нода один раз сообщает о себе и на этом останавливается: heartbeat не отправляется, и панель не показывает её как online. Команды из панели, стрим логов и метрики появятся вместе с туннелем платформы (задача NODE-002 на стороне платформы).

🔗 Связанные задачи ​

DMN-058, DMN-127 (сертификат от платформы), DMN-129 (API через веб-сервер ноды) в ROADMAP; на стороне платформы — NODE-001 (реестр нод и токены регистрации) и NODE-002 (канал платформа ↔ демон).

Распространяется по лицензии MIT.